diff --git a/prdoc/pr_4823.prdoc b/prdoc/pr_4823.prdoc
new file mode 100644
index 0000000000000000000000000000000000000000..a498b33f7bfa949078ca23ac196116b7f5b2f1f9
--- /dev/null
+++ b/prdoc/pr_4823.prdoc
@@ -0,0 +1,11 @@
+title: "`pallet-referenda`: Ensure to schedule referendas earliest at the next block"
+
+doc:
+  - audience: Runtime User
+    description: |
+      Ensure that referendas are scheduled earliest at the next block when they are enacted.
+      Otherwise the scheduling may fails and thus, the enactment of the referenda.
+
+crates:
+  - name: pallet-referenda
+    bump: patch
diff --git a/substrate/frame/referenda/src/lib.rs b/substrate/frame/referenda/src/lib.rs
index fbe27e1a4784733f517bb6ee3259ebdc4b1075b3..0cdf450d3b6c98e942e3613210f31eb34098b008 100644
--- a/substrate/frame/referenda/src/lib.rs
+++ b/substrate/frame/referenda/src/lib.rs
@@ -891,7 +891,8 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
 		call: BoundedCallOf<T, I>,
 	) {
 		let now = frame_system::Pallet::<T>::block_number();
-		let earliest_allowed = now.saturating_add(track.min_enactment_period);
+		// Earliest allowed block is always at minimum the next block.
+		let earliest_allowed = now.saturating_add(track.min_enactment_period.max(One::one()));
 		let desired = desired.evaluate(now);
 		let ok = T::Scheduler::schedule_named(
 			(ASSEMBLY_ID, "enactment", index).using_encoded(sp_io::hashing::blake2_256),
diff --git a/substrate/frame/referenda/src/mock.rs b/substrate/frame/referenda/src/mock.rs
index d47da45581195b43328d081ea3373a36487847d3..bf0fa4e1a12e17a90f2d35fd555d5805765b26be 100644
--- a/substrate/frame/referenda/src/mock.rs
+++ b/substrate/frame/referenda/src/mock.rs
@@ -112,7 +112,7 @@ impl TracksInfo<u64, u64> for TestTracksInfo {
 	type Id = u8;
 	type RuntimeOrigin = <RuntimeOrigin as OriginTrait>::PalletsOrigin;
 	fn tracks() -> &'static [(Self::Id, TrackInfo<u64, u64>)] {
-		static DATA: [(u8, TrackInfo<u64, u64>); 2] = [
+		static DATA: [(u8, TrackInfo<u64, u64>); 3] = [
 			(
 				0u8,
 				TrackInfo {
@@ -157,6 +157,28 @@ impl TracksInfo<u64, u64> for TestTracksInfo {
 					},
 				},
 			),
+			(
+				2u8,
+				TrackInfo {
+					name: "none",
+					max_deciding: 3,
+					decision_deposit: 1,
+					prepare_period: 2,
+					decision_period: 2,
+					confirm_period: 1,
+					min_enactment_period: 0,
+					min_approval: Curve::LinearDecreasing {
+						length: Perbill::from_percent(100),
+						floor: Perbill::from_percent(95),
+						ceil: Perbill::from_percent(100),
+					},
+					min_support: Curve::LinearDecreasing {
+						length: Perbill::from_percent(100),
+						floor: Perbill::from_percent(90),
+						ceil: Perbill::from_percent(100),
+					},
+				},
+			),
 		];
 		&DATA[..]
 	}
@@ -165,6 +187,7 @@ impl TracksInfo<u64, u64> for TestTracksInfo {
 			match system_origin {
 				frame_system::RawOrigin::Root => Ok(0),
 				frame_system::RawOrigin::None => Ok(1),
+				frame_system::RawOrigin::Signed(1) => Ok(2),
 				_ => Err(()),
 			}
 		} else {
diff --git a/substrate/frame/referenda/src/tests.rs b/substrate/frame/referenda/src/tests.rs
index 52251fcbdbeed0ec5b8830e87a2a4c66bb265e39..3f859636f7cbb34d36d9fbafdfa05c189905d2c6 100644
--- a/substrate/frame/referenda/src/tests.rs
+++ b/substrate/frame/referenda/src/tests.rs
@@ -682,3 +682,27 @@ fn detects_incorrect_len() {
 		);
 	});
 }
+
+/// Ensures that `DispatchTime::After(0)` plus `min_enactment_period = 0` works.
+#[test]
+fn zero_enactment_delay_executes_proposal_at_next_block() {
+	ExtBuilder::default().build_and_execute(|| {
+		assert_eq!(Balances::free_balance(42), 0);
+		assert_ok!(Referenda::submit(
+			RuntimeOrigin::signed(1),
+			Box::new(RawOrigin::Signed(1).into()),
+			Preimage::bound(
+				pallet_balances::Call::transfer_keep_alive { dest: 42, value: 20 }.into()
+			)
+			.unwrap(),
+			DispatchTime::After(0),
+		));
+		assert_ok!(Referenda::place_decision_deposit(RuntimeOrigin::signed(1), 0));
+		assert_eq!(ReferendumCount::<Test>::get(), 1);
+		set_tally(0, 100, 0);
+
+		run_to(9);
+
+		assert_eq!(Balances::free_balance(42), 20);
+	});
+}