diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/ambassador/mod.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/ambassador/mod.rs
index a052a9d3800cc6880ccee84358883194cb46eb80..8b0842697237fb51b0097b49d8f74b18fab32970 100644
--- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/ambassador/mod.rs
+++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/ambassador/mod.rs
@@ -154,6 +154,7 @@ impl pallet_referenda::Config<AmbassadorReferendaInstance> for Runtime {
 	type AlarmInterval = AlarmInterval;
 	type Tracks = tracks::TracksInfo;
 	type Preimages = Preimage;
+	type BlockNumberProvider = System;
 }
 
 parameter_types! {
diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/fellowship/mod.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/fellowship/mod.rs
index 1e8212cf6ac280a358fe168fc1e22d1eed6fc274..e699f2eeaf43862d204d8f21e400acab3da6cbe1 100644
--- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/fellowship/mod.rs
+++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/fellowship/mod.rs
@@ -106,6 +106,7 @@ impl pallet_referenda::Config<FellowshipReferendaInstance> for Runtime {
 	type AlarmInterval = ConstU32<1>;
 	type Tracks = tracks::TracksInfo;
 	type Preimages = Preimage;
+	type BlockNumberProvider = crate::System;
 }
 
 pub type FellowshipCollectiveInstance = pallet_ranked_collective::Instance1;
diff --git a/polkadot/runtime/rococo/src/governance/fellowship.rs b/polkadot/runtime/rococo/src/governance/fellowship.rs
index 27a58a0eebd183bc5d21efa655113cf3a0251cc0..231defab6aa52419b42131a510637e0b1c04c889 100644
--- a/polkadot/runtime/rococo/src/governance/fellowship.rs
+++ b/polkadot/runtime/rococo/src/governance/fellowship.rs
@@ -308,6 +308,7 @@ impl pallet_referenda::Config<FellowshipReferendaInstance> for Runtime {
 	type AlarmInterval = AlarmInterval;
 	type Tracks = TracksInfo;
 	type Preimages = Preimage;
+	type BlockNumberProvider = System;
 }
 
 pub type FellowshipCollectiveInstance = pallet_ranked_collective::Instance1;
diff --git a/polkadot/runtime/rococo/src/governance/mod.rs b/polkadot/runtime/rococo/src/governance/mod.rs
index ef2adf60753d541c44eaf6073a3a012e66bf9f5c..2be549be29ed14a80c3856cc0db2fa359c83cbcc 100644
--- a/polkadot/runtime/rococo/src/governance/mod.rs
+++ b/polkadot/runtime/rococo/src/governance/mod.rs
@@ -90,4 +90,5 @@ impl pallet_referenda::Config for Runtime {
 	type AlarmInterval = AlarmInterval;
 	type Tracks = TracksInfo;
 	type Preimages = Preimage;
+	type BlockNumberProvider = System;
 }
diff --git a/polkadot/runtime/westend/src/governance/mod.rs b/polkadot/runtime/westend/src/governance/mod.rs
index d027f788d71f6bf255b71157bfe21ba1fdc16f5a..abc25ebaa470833a9bd188b5747ac641638a2fcc 100644
--- a/polkadot/runtime/westend/src/governance/mod.rs
+++ b/polkadot/runtime/westend/src/governance/mod.rs
@@ -94,4 +94,5 @@ impl pallet_referenda::Config for Runtime {
 	type AlarmInterval = AlarmInterval;
 	type Tracks = TracksInfo;
 	type Preimages = Preimage;
+	type BlockNumberProvider = System;
 }
diff --git a/prdoc/pr_6338.prdoc b/prdoc/pr_6338.prdoc
new file mode 100644
index 0000000000000000000000000000000000000000..68d01904d071975de79188b98ba06cd8aaae8bc7
--- /dev/null
+++ b/prdoc/pr_6338.prdoc
@@ -0,0 +1,14 @@
+# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0
+# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json
+
+title: Update Referenda to Support Block Number Provider
+
+doc:
+  - audience: Runtime Dev
+    description: |
+      This PR makes the referenda pallet uses the relay chain as a block provider for a parachain on a regular schedule.
+      To migrate existing referenda implementations, simply add `type BlockNumberProvider = System` to have the same behavior as before.
+
+crates:
+- name: pallet-referenda
+  bump: major
\ No newline at end of file
diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs
index 905b8735c5df9411e2a85f036159ff0a6968f00c..610ef4fb629a106bf4fc990b7bb6e88bb22da52d 100644
--- a/substrate/bin/node/runtime/src/lib.rs
+++ b/substrate/bin/node/runtime/src/lib.rs
@@ -1073,6 +1073,7 @@ impl pallet_referenda::Config for Runtime {
 	type AlarmInterval = AlarmInterval;
 	type Tracks = TracksInfo;
 	type Preimages = Preimage;
+	type BlockNumberProvider = System;
 }
 
 impl pallet_referenda::Config<pallet_referenda::Instance2> for Runtime {
@@ -1093,6 +1094,7 @@ impl pallet_referenda::Config<pallet_referenda::Instance2> for Runtime {
 	type AlarmInterval = AlarmInterval;
 	type Tracks = TracksInfo;
 	type Preimages = Preimage;
+	type BlockNumberProvider = System;
 }
 
 impl pallet_ranked_collective::Config for Runtime {
diff --git a/substrate/frame/referenda/src/benchmarking.rs b/substrate/frame/referenda/src/benchmarking.rs
index 67ac82787d31d78a859ed0158d7f6be2b1276aea..895f95dbec556e77781f9d46f2cf552ed8cb0956 100644
--- a/substrate/frame/referenda/src/benchmarking.rs
+++ b/substrate/frame/referenda/src/benchmarking.rs
@@ -33,6 +33,10 @@ use sp_runtime::traits::Bounded as ArithBounded;
 
 const SEED: u32 = 0;
 
+fn set_block_number<T: Config<I>, I: 'static>(n: BlockNumberFor<T, I>) {
+	<T as Config<I>>::BlockNumberProvider::set_block_number(n);
+}
+
 fn assert_last_event<T: Config<I>, I: 'static>(generic_event: <T as Config<I>>::RuntimeEvent) {
 	frame_system::Pallet::<T>::assert_last_event(generic_event.into());
 }
@@ -151,30 +155,28 @@ fn make_failing<T: Config<I>, I: 'static>(index: ReferendumIndex) {
 fn skip_prepare_period<T: Config<I>, I: 'static>(index: ReferendumIndex) {
 	let status = Referenda::<T, I>::ensure_ongoing(index).unwrap();
 	let prepare_period_over = status.submitted + info::<T, I>(index).prepare_period;
-	frame_system::Pallet::<T>::set_block_number(prepare_period_over);
+	set_block_number::<T, I>(prepare_period_over);
 }
 
 fn skip_decision_period<T: Config<I>, I: 'static>(index: ReferendumIndex) {
 	let status = Referenda::<T, I>::ensure_ongoing(index).unwrap();
 	let decision_period_over = status.deciding.unwrap().since + info::<T, I>(index).decision_period;
-	frame_system::Pallet::<T>::set_block_number(decision_period_over);
+	set_block_number::<T, I>(decision_period_over);
 }
 
 fn skip_confirm_period<T: Config<I>, I: 'static>(index: ReferendumIndex) {
 	let status = Referenda::<T, I>::ensure_ongoing(index).unwrap();
 	let confirm_period_over = status.deciding.unwrap().confirming.unwrap();
-	frame_system::Pallet::<T>::set_block_number(confirm_period_over);
+	set_block_number::<T, I>(confirm_period_over);
 }
 
 fn skip_timeout_period<T: Config<I>, I: 'static>(index: ReferendumIndex) {
 	let status = Referenda::<T, I>::ensure_ongoing(index).unwrap();
 	let timeout_period_over = status.submitted + T::UndecidingTimeout::get();
-	frame_system::Pallet::<T>::set_block_number(timeout_period_over);
+	set_block_number::<T, I>(timeout_period_over);
 }
 
-fn alarm_time<T: Config<I>, I: 'static>(
-	index: ReferendumIndex,
-) -> frame_system::pallet_prelude::BlockNumberFor<T> {
+fn alarm_time<T: Config<I>, I: 'static>(index: ReferendumIndex) -> BlockNumberFor<T, I> {
 	let status = Referenda::<T, I>::ensure_ongoing(index).unwrap();
 	status.alarm.unwrap().0
 }
diff --git a/substrate/frame/referenda/src/lib.rs b/substrate/frame/referenda/src/lib.rs
index e72dd7f11cbb2f8f17f32ec9d9b1768ee015ec2d..e6a895f9c5933961a831525035f7201d9e20cbe3 100644
--- a/substrate/frame/referenda/src/lib.rs
+++ b/substrate/frame/referenda/src/lib.rs
@@ -82,7 +82,6 @@ use frame_support::{
 	},
 	BoundedVec,
 };
-use frame_system::pallet_prelude::BlockNumberFor;
 use scale_info::TypeInfo;
 use sp_runtime::{
 	traits::{AtLeast32BitUnsigned, Bounded, Dispatchable, One, Saturating, Zero},
@@ -98,14 +97,15 @@ use self::branch::{BeginDecidingBranch, OneFewerDecidingBranch, ServiceBranch};
 pub use self::{
 	pallet::*,
 	types::{
-		BalanceOf, BoundedCallOf, CallOf, Curve, DecidingStatus, DecidingStatusOf, Deposit,
-		InsertSorted, NegativeImbalanceOf, PalletsOriginOf, ReferendumIndex, ReferendumInfo,
-		ReferendumInfoOf, ReferendumStatus, ReferendumStatusOf, ScheduleAddressOf, TallyOf,
-		TrackIdOf, TrackInfo, TrackInfoOf, TracksInfo, VotesOf,
+		BalanceOf, BlockNumberFor, BoundedCallOf, CallOf, Curve, DecidingStatus, DecidingStatusOf,
+		Deposit, InsertSorted, NegativeImbalanceOf, PalletsOriginOf, ReferendumIndex,
+		ReferendumInfo, ReferendumInfoOf, ReferendumStatus, ReferendumStatusOf, ScheduleAddressOf,
+		TallyOf, TrackIdOf, TrackInfo, TrackInfoOf, TracksInfo, VotesOf,
 	},
 	weights::WeightInfo,
 };
 pub use alloc::vec::Vec;
+use sp_runtime::traits::BlockNumberProvider;
 
 #[cfg(test)]
 mod mock;
@@ -144,7 +144,10 @@ const ASSEMBLY_ID: LockIdentifier = *b"assembly";
 pub mod pallet {
 	use super::*;
 	use frame_support::{pallet_prelude::*, traits::EnsureOriginWithArg};
-	use frame_system::pallet_prelude::*;
+	use frame_system::pallet_prelude::{
+		ensure_root, ensure_signed, ensure_signed_or_root, BlockNumberFor as SystemBlockNumberFor,
+		OriginFor,
+	};
 
 	/// The in-code storage version.
 	const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
@@ -167,12 +170,12 @@ pub mod pallet {
 		type WeightInfo: WeightInfo;
 		/// The Scheduler.
 		type Scheduler: ScheduleAnon<
-				BlockNumberFor<Self>,
+				BlockNumberFor<Self, I>,
 				CallOf<Self, I>,
 				PalletsOriginOf<Self>,
 				Hasher = Self::Hashing,
 			> + ScheduleNamed<
-				BlockNumberFor<Self>,
+				BlockNumberFor<Self, I>,
 				CallOf<Self, I>,
 				PalletsOriginOf<Self>,
 				Hasher = Self::Hashing,
@@ -215,30 +218,35 @@ pub mod pallet {
 		/// The number of blocks after submission that a referendum must begin being decided by.
 		/// Once this passes, then anyone may cancel the referendum.
 		#[pallet::constant]
-		type UndecidingTimeout: Get<BlockNumberFor<Self>>;
+		type UndecidingTimeout: Get<BlockNumberFor<Self, I>>;
 
 		/// Quantization level for the referendum wakeup scheduler. A higher number will result in
 		/// fewer storage reads/writes needed for smaller voters, but also result in delays to the
 		/// automatic referendum status changes. Explicit servicing instructions are unaffected.
 		#[pallet::constant]
-		type AlarmInterval: Get<BlockNumberFor<Self>>;
+		type AlarmInterval: Get<BlockNumberFor<Self, I>>;
 
 		// The other stuff.
 		/// Information concerning the different referendum tracks.
 		#[pallet::constant]
 		type Tracks: Get<
 				Vec<(
-					<Self::Tracks as TracksInfo<BalanceOf<Self, I>, BlockNumberFor<Self>>>::Id,
-					TrackInfo<BalanceOf<Self, I>, BlockNumberFor<Self>>,
+					<Self::Tracks as TracksInfo<BalanceOf<Self, I>, BlockNumberFor<Self, I>>>::Id,
+					TrackInfo<BalanceOf<Self, I>, BlockNumberFor<Self, I>>,
 				)>,
 			> + TracksInfo<
 				BalanceOf<Self, I>,
-				BlockNumberFor<Self>,
+				BlockNumberFor<Self, I>,
 				RuntimeOrigin = <Self::RuntimeOrigin as OriginTrait>::PalletsOrigin,
 			>;
 
 		/// The preimage provider.
 		type Preimages: QueryPreimage<H = Self::Hashing> + StorePreimage;
+
+		/// Provider for the block number.
+		///
+		/// Normally this is the `frame_system` pallet.
+		type BlockNumberProvider: BlockNumberProvider;
 	}
 
 	/// The next free referendum index, aka the number of referenda started so far.
@@ -432,9 +440,9 @@ pub mod pallet {
 	}
 
 	#[pallet::hooks]
-	impl<T: Config<I>, I: 'static> Hooks<BlockNumberFor<T>> for Pallet<T, I> {
+	impl<T: Config<I>, I: 'static> Hooks<SystemBlockNumberFor<T>> for Pallet<T, I> {
 		#[cfg(feature = "try-runtime")]
-		fn try_state(_n: BlockNumberFor<T>) -> Result<(), sp_runtime::TryRuntimeError> {
+		fn try_state(_n: SystemBlockNumberFor<T>) -> Result<(), sp_runtime::TryRuntimeError> {
 			Self::do_try_state()?;
 			Ok(())
 		}
@@ -462,7 +470,7 @@ pub mod pallet {
 			origin: OriginFor<T>,
 			proposal_origin: Box<PalletsOriginOf<T>>,
 			proposal: BoundedCallOf<T, I>,
-			enactment_moment: DispatchTime<BlockNumberFor<T>>,
+			enactment_moment: DispatchTime<BlockNumberFor<T, I>>,
 		) -> DispatchResult {
 			let proposal_origin = *proposal_origin;
 			let who = T::SubmitOrigin::ensure_origin(origin, &proposal_origin)?;
@@ -485,7 +493,7 @@ pub mod pallet {
 				*x += 1;
 				r
 			});
-			let now = frame_system::Pallet::<T>::block_number();
+			let now = T::BlockNumberProvider::current_block_number();
 			let nudge_call =
 				T::Preimages::bound(CallOf::<T, I>::from(Call::nudge_referendum { index }))?;
 			let status = ReferendumStatus {
@@ -527,7 +535,7 @@ pub mod pallet {
 			let track = Self::track(status.track).ok_or(Error::<T, I>::NoTrack)?;
 			status.decision_deposit =
 				Some(Self::take_deposit(who.clone(), track.decision_deposit)?);
-			let now = frame_system::Pallet::<T>::block_number();
+			let now = T::BlockNumberProvider::current_block_number();
 			let (info, _, branch) = Self::service_referendum(now, index, status);
 			ReferendumInfoFor::<T, I>::insert(index, info);
 			let e =
@@ -584,7 +592,7 @@ pub mod pallet {
 			Self::note_one_fewer_deciding(status.track);
 			Self::deposit_event(Event::<T, I>::Cancelled { index, tally: status.tally });
 			let info = ReferendumInfo::Cancelled(
-				frame_system::Pallet::<T>::block_number(),
+				T::BlockNumberProvider::current_block_number(),
 				Some(status.submission_deposit),
 				status.decision_deposit,
 			);
@@ -611,7 +619,7 @@ pub mod pallet {
 			Self::slash_deposit(Some(status.submission_deposit.clone()));
 			Self::slash_deposit(status.decision_deposit.clone());
 			Self::do_clear_metadata(index);
-			let info = ReferendumInfo::Killed(frame_system::Pallet::<T>::block_number());
+			let info = ReferendumInfo::Killed(T::BlockNumberProvider::current_block_number());
 			ReferendumInfoFor::<T, I>::insert(index, info);
 			Ok(())
 		}
@@ -627,7 +635,7 @@ pub mod pallet {
 			index: ReferendumIndex,
 		) -> DispatchResultWithPostInfo {
 			ensure_root(origin)?;
-			let now = frame_system::Pallet::<T>::block_number();
+			let now = T::BlockNumberProvider::current_block_number();
 			let mut status = Self::ensure_ongoing(index)?;
 			// This is our wake-up, so we can disregard the alarm.
 			status.alarm = None;
@@ -658,7 +666,7 @@ pub mod pallet {
 			let mut track_queue = TrackQueue::<T, I>::get(track);
 			let branch =
 				if let Some((index, mut status)) = Self::next_for_deciding(&mut track_queue) {
-					let now = frame_system::Pallet::<T>::block_number();
+					let now = T::BlockNumberProvider::current_block_number();
 					let (maybe_alarm, branch) =
 						Self::begin_deciding(&mut status, index, now, track_info);
 					if let Some(set_alarm) = maybe_alarm {
@@ -744,7 +752,7 @@ pub mod pallet {
 impl<T: Config<I>, I: 'static> Polling<T::Tally> for Pallet<T, I> {
 	type Index = ReferendumIndex;
 	type Votes = VotesOf<T, I>;
-	type Moment = BlockNumberFor<T>;
+	type Moment = BlockNumberFor<T, I>;
 	type Class = TrackIdOf<T, I>;
 
 	fn classes() -> Vec<Self::Class> {
@@ -753,12 +761,12 @@ impl<T: Config<I>, I: 'static> Polling<T::Tally> for Pallet<T, I> {
 
 	fn access_poll<R>(
 		index: Self::Index,
-		f: impl FnOnce(PollStatus<&mut T::Tally, BlockNumberFor<T>, TrackIdOf<T, I>>) -> R,
+		f: impl FnOnce(PollStatus<&mut T::Tally, BlockNumberFor<T, I>, TrackIdOf<T, I>>) -> R,
 	) -> R {
 		match ReferendumInfoFor::<T, I>::get(index) {
 			Some(ReferendumInfo::Ongoing(mut status)) => {
 				let result = f(PollStatus::Ongoing(&mut status.tally, status.track));
-				let now = frame_system::Pallet::<T>::block_number();
+				let now = T::BlockNumberProvider::current_block_number();
 				Self::ensure_alarm_at(&mut status, index, now + One::one());
 				ReferendumInfoFor::<T, I>::insert(index, ReferendumInfo::Ongoing(status));
 				result
@@ -772,13 +780,13 @@ impl<T: Config<I>, I: 'static> Polling<T::Tally> for Pallet<T, I> {
 	fn try_access_poll<R>(
 		index: Self::Index,
 		f: impl FnOnce(
-			PollStatus<&mut T::Tally, BlockNumberFor<T>, TrackIdOf<T, I>>,
+			PollStatus<&mut T::Tally, BlockNumberFor<T, I>, TrackIdOf<T, I>>,
 		) -> Result<R, DispatchError>,
 	) -> Result<R, DispatchError> {
 		match ReferendumInfoFor::<T, I>::get(index) {
 			Some(ReferendumInfo::Ongoing(mut status)) => {
 				let result = f(PollStatus::Ongoing(&mut status.tally, status.track))?;
-				let now = frame_system::Pallet::<T>::block_number();
+				let now = T::BlockNumberProvider::current_block_number();
 				Self::ensure_alarm_at(&mut status, index, now + One::one());
 				ReferendumInfoFor::<T, I>::insert(index, ReferendumInfo::Ongoing(status));
 				Ok(result)
@@ -800,7 +808,7 @@ impl<T: Config<I>, I: 'static> Polling<T::Tally> for Pallet<T, I> {
 			*x += 1;
 			r
 		});
-		let now = frame_system::Pallet::<T>::block_number();
+		let now = T::BlockNumberProvider::current_block_number();
 		let dummy_account_id =
 			codec::Decode::decode(&mut sp_runtime::traits::TrailingZeroInput::new(&b"dummy"[..]))
 				.expect("infinite length input; no invalid inputs for type; qed");
@@ -828,7 +836,7 @@ impl<T: Config<I>, I: 'static> Polling<T::Tally> for Pallet<T, I> {
 		let mut status = Self::ensure_ongoing(index).map_err(|_| ())?;
 		Self::ensure_no_alarm(&mut status);
 		Self::note_one_fewer_deciding(status.track);
-		let now = frame_system::Pallet::<T>::block_number();
+		let now = T::BlockNumberProvider::current_block_number();
 		let info = if approved {
 			ReferendumInfo::Approved(now, Some(status.submission_deposit), status.decision_deposit)
 		} else {
@@ -868,7 +876,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
 			ReferendumInfo::Ongoing(status) => {
 				let track = Self::track(status.track).ok_or(Error::<T, I>::NoTrack)?;
 				let elapsed = if let Some(deciding) = status.deciding {
-					frame_system::Pallet::<T>::block_number().saturating_sub(deciding.since)
+					T::BlockNumberProvider::current_block_number().saturating_sub(deciding.since)
 				} else {
 					Zero::zero()
 				};
@@ -889,11 +897,11 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
 	fn schedule_enactment(
 		index: ReferendumIndex,
 		track: &TrackInfoOf<T, I>,
-		desired: DispatchTime<BlockNumberFor<T>>,
+		desired: DispatchTime<BlockNumberFor<T, I>>,
 		origin: PalletsOriginOf<T>,
 		call: BoundedCallOf<T, I>,
 	) {
-		let now = frame_system::Pallet::<T>::block_number();
+		let now = T::BlockNumberProvider::current_block_number();
 		// 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);
@@ -912,8 +920,8 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
 	/// Set an alarm to dispatch `call` at block number `when`.
 	fn set_alarm(
 		call: BoundedCallOf<T, I>,
-		when: BlockNumberFor<T>,
-	) -> Option<(BlockNumberFor<T>, ScheduleAddressOf<T, I>)> {
+		when: BlockNumberFor<T, I>,
+	) -> Option<(BlockNumberFor<T, I>, ScheduleAddressOf<T, I>)> {
 		let alarm_interval = T::AlarmInterval::get().max(One::one());
 		// Alarm must go off no earlier than `when`.
 		// This rounds `when` upwards to the next multiple of `alarm_interval`.
@@ -931,7 +939,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
 			result.is_ok(),
 			"Unable to schedule a new alarm at #{:?} (now: #{:?}), scheduler error: `{:?}`",
 			when,
-			frame_system::Pallet::<T>::block_number(),
+			T::BlockNumberProvider::current_block_number(),
 			result.unwrap_err(),
 		);
 		result.ok().map(|x| (when, x))
@@ -946,9 +954,9 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
 	fn begin_deciding(
 		status: &mut ReferendumStatusOf<T, I>,
 		index: ReferendumIndex,
-		now: BlockNumberFor<T>,
+		now: BlockNumberFor<T, I>,
 		track: &TrackInfoOf<T, I>,
-	) -> (Option<BlockNumberFor<T>>, BeginDecidingBranch) {
+	) -> (Option<BlockNumberFor<T, I>>, BeginDecidingBranch) {
 		let is_passing = Self::is_passing(
 			&status.tally,
 			Zero::zero(),
@@ -984,11 +992,11 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
 	///
 	/// If `None`, then it is queued and should be nudged automatically as the queue gets drained.
 	fn ready_for_deciding(
-		now: BlockNumberFor<T>,
+		now: BlockNumberFor<T, I>,
 		track: &TrackInfoOf<T, I>,
 		index: ReferendumIndex,
 		status: &mut ReferendumStatusOf<T, I>,
-	) -> (Option<BlockNumberFor<T>>, ServiceBranch) {
+	) -> (Option<BlockNumberFor<T, I>>, ServiceBranch) {
 		let deciding_count = DecidingCount::<T, I>::get(status.track);
 		if deciding_count < track.max_deciding {
 			// Begin deciding.
@@ -1023,7 +1031,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
 	/// overall more efficient), however the weights become rather less easy to measure.
 	fn note_one_fewer_deciding(track: TrackIdOf<T, I>) {
 		// Set an alarm call for the next block to nudge the track along.
-		let now = frame_system::Pallet::<T>::block_number();
+		let now = T::BlockNumberProvider::current_block_number();
 		let next_block = now + One::one();
 		let call = match T::Preimages::bound(CallOf::<T, I>::from(Call::one_fewer_deciding {
 			track,
@@ -1045,7 +1053,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
 	fn ensure_alarm_at(
 		status: &mut ReferendumStatusOf<T, I>,
 		index: ReferendumIndex,
-		alarm: BlockNumberFor<T>,
+		alarm: BlockNumberFor<T, I>,
 	) -> bool {
 		if status.alarm.as_ref().map_or(true, |&(when, _)| when != alarm) {
 			// Either no alarm or one that was different
@@ -1090,7 +1098,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
 	/// `TrackQueue`. Basically this happens when a referendum is in the deciding queue and receives
 	/// a vote, or when it moves into the deciding queue.
 	fn service_referendum(
-		now: BlockNumberFor<T>,
+		now: BlockNumberFor<T, I>,
 		index: ReferendumIndex,
 		mut status: ReferendumStatusOf<T, I>,
 	) -> (ReferendumInfoOf<T, I>, bool, ServiceBranch) {
@@ -1102,7 +1110,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
 		};
 		// Default the alarm to the end of the world.
 		let timeout = status.submitted + T::UndecidingTimeout::get();
-		let mut alarm = BlockNumberFor::<T>::max_value();
+		let mut alarm = BlockNumberFor::<T, I>::max_value();
 		let branch;
 		match &mut status.deciding {
 			None => {
@@ -1233,7 +1241,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
 			},
 		}
 
-		let dirty_alarm = if alarm < BlockNumberFor::<T>::max_value() {
+		let dirty_alarm = if alarm < BlockNumberFor::<T, I>::max_value() {
 			Self::ensure_alarm_at(&mut status, index, alarm)
 		} else {
 			Self::ensure_no_alarm(&mut status)
@@ -1244,11 +1252,11 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
 	/// Determine the point at which a referendum will be accepted, move into confirmation with the
 	/// given `tally` or end with rejection (whichever happens sooner).
 	fn decision_time(
-		deciding: &DecidingStatusOf<T>,
+		deciding: &DecidingStatusOf<T, I>,
 		tally: &T::Tally,
 		track_id: TrackIdOf<T, I>,
 		track: &TrackInfoOf<T, I>,
-	) -> BlockNumberFor<T> {
+	) -> BlockNumberFor<T, I> {
 		deciding.confirming.unwrap_or_else(|| {
 			// Set alarm to the point where the current voting would make it pass.
 			let approval = tally.approval(track_id);
@@ -1307,8 +1315,8 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
 	/// `approval_needed`.
 	fn is_passing(
 		tally: &T::Tally,
-		elapsed: BlockNumberFor<T>,
-		period: BlockNumberFor<T>,
+		elapsed: BlockNumberFor<T, I>,
+		period: BlockNumberFor<T, I>,
 		support_needed: &Curve,
 		approval_needed: &Curve,
 		id: TrackIdOf<T, I>,
@@ -1377,7 +1385,9 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
 					if let Some(deciding) = status.deciding {
 						ensure!(
 							deciding.since <
-								deciding.confirming.unwrap_or(BlockNumberFor::<T>::max_value()),
+								deciding
+									.confirming
+									.unwrap_or(BlockNumberFor::<T, I>::max_value()),
 							"Deciding status cannot begin before confirming stage."
 						)
 					}
diff --git a/substrate/frame/referenda/src/migration.rs b/substrate/frame/referenda/src/migration.rs
index 631eb7340e567e8115e1755d513980fb148700c5..c94896649beab7c59a1941755959013480f20475 100644
--- a/substrate/frame/referenda/src/migration.rs
+++ b/substrate/frame/referenda/src/migration.rs
@@ -25,6 +25,8 @@ use log;
 #[cfg(feature = "try-runtime")]
 use sp_runtime::TryRuntimeError;
 
+type SystemBlockNumberFor<T> = frame_system::pallet_prelude::BlockNumberFor<T>;
+
 /// Initial version of storage types.
 pub mod v0 {
 	use super::*;
@@ -37,7 +39,7 @@ pub mod v0 {
 	pub type ReferendumInfoOf<T, I> = ReferendumInfo<
 		TrackIdOf<T, I>,
 		PalletsOriginOf<T>,
-		frame_system::pallet_prelude::BlockNumberFor<T>,
+		SystemBlockNumberFor<T>,
 		BoundedCallOf<T, I>,
 		BalanceOf<T, I>,
 		TallyOf<T, I>,
@@ -93,6 +95,21 @@ pub mod v1 {
 	/// The log target.
 	const TARGET: &'static str = "runtime::referenda::migration::v1";
 
+	pub(crate) type ReferendumInfoOf<T, I> = ReferendumInfo<
+		TrackIdOf<T, I>,
+		PalletsOriginOf<T>,
+		SystemBlockNumberFor<T>,
+		BoundedCallOf<T, I>,
+		BalanceOf<T, I>,
+		TallyOf<T, I>,
+		<T as frame_system::Config>::AccountId,
+		ScheduleAddressOf<T, I>,
+	>;
+
+	#[storage_alias]
+	pub type ReferendumInfoFor<T: Config<I>, I: 'static> =
+		StorageMap<Pallet<T, I>, Blake2_128Concat, ReferendumIndex, ReferendumInfoOf<T, I>>;
+
 	/// Transforms a submission deposit of ReferendumInfo(Approved|Rejected|Cancelled|TimedOut) to
 	/// optional value, making it refundable.
 	pub struct MigrateV0ToV1<T, I = ()>(PhantomData<(T, I)>);
@@ -137,7 +154,7 @@ pub mod v1 {
 				if let Some(new_value) = maybe_new_value {
 					weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1));
 					log::info!(target: TARGET, "migrating referendum #{:?}", &key);
-					ReferendumInfoFor::<T, I>::insert(key, new_value);
+					v1::ReferendumInfoFor::<T, I>::insert(key, new_value);
 				} else {
 					weight.saturating_accrue(T::DbWeight::get().reads(1));
 				}
@@ -161,10 +178,125 @@ pub mod v1 {
 	}
 }
 
+/// Migration for when changing the block number provider.
+///
+/// This migration is not guarded
+pub mod switch_block_number_provider {
+	use super::*;
+
+	/// The log target.
+	const TARGET: &'static str = "runtime::referenda::migration::change_block_number_provider";
+	/// Convert from one to another block number provider/type.
+	pub trait BlockNumberConversion<Old, New> {
+		/// Convert the `old` block number type to the new block number type.
+		///
+		/// Any changes in the rate of blocks need to be taken into account.
+		fn convert_block_number(block_number: Old) -> New;
+	}
+
+	/// Transforms `SystemBlockNumberFor<T>` to `BlockNumberFor<T,I>`
+	pub struct MigrateBlockNumberProvider<BlockConverter, T, I = ()>(
+		PhantomData<(T, I)>,
+		PhantomData<BlockConverter>,
+	);
+	impl<BlockConverter: BlockNumberConversion<T, I>, T: Config<I>, I: 'static> OnRuntimeUpgrade
+		for MigrateBlockNumberProvider<BlockConverter, T, I>
+	where
+		BlockConverter: BlockNumberConversion<SystemBlockNumberFor<T>, BlockNumberFor<T, I>>,
+		T: Config<I>,
+	{
+		#[cfg(feature = "try-runtime")]
+		fn pre_upgrade() -> Result<Vec<u8>, TryRuntimeError> {
+			let referendum_count = v1::ReferendumInfoFor::<T, I>::iter().count();
+			log::info!(
+				target: TARGET,
+				"pre-upgrade state contains '{}' referendums.",
+				referendum_count
+			);
+			Ok((referendum_count as u32).encode())
+		}
+
+		fn on_runtime_upgrade() -> Weight {
+			let mut weight = Weight::zero();
+			weight.saturating_accrue(migrate_block_number_provider::<BlockConverter, T, I>());
+			weight
+		}
+
+		#[cfg(feature = "try-runtime")]
+		fn post_upgrade(state: Vec<u8>) -> Result<(), TryRuntimeError> {
+			let on_chain_version = Pallet::<T, I>::on_chain_storage_version();
+			ensure!(on_chain_version == 1, "must upgrade from version 1 to 2.");
+			let pre_referendum_count: u32 = Decode::decode(&mut &state[..])
+				.expect("failed to decode the state from pre-upgrade.");
+			let post_referendum_count = ReferendumInfoFor::<T, I>::iter().count() as u32;
+			ensure!(post_referendum_count == pre_referendum_count, "must migrate all referendums.");
+			log::info!(target: TARGET, "migrated all referendums.");
+			Ok(())
+		}
+	}
+
+	pub fn migrate_block_number_provider<BlockConverter, T, I: 'static>() -> Weight
+	where
+		BlockConverter: BlockNumberConversion<SystemBlockNumberFor<T>, BlockNumberFor<T, I>>,
+		T: Config<I>,
+	{
+		let in_code_version = Pallet::<T, I>::in_code_storage_version();
+		let on_chain_version = Pallet::<T, I>::on_chain_storage_version();
+		let mut weight = T::DbWeight::get().reads(1);
+		log::info!(
+			target: "runtime::referenda::migration::change_block_number_provider",
+			"running migration with in-code storage version {:?} / onchain {:?}.",
+			in_code_version,
+			on_chain_version
+		);
+		if on_chain_version == 0 {
+			log::error!(target: TARGET, "skipping migration from v0 to switch_block_number_provider.");
+			return weight
+		}
+
+		// Migration logic here
+		v1::ReferendumInfoFor::<T, I>::iter().for_each(|(key, value)| {
+			let maybe_new_value = match value {
+				ReferendumInfo::Ongoing(_) | ReferendumInfo::Killed(_) => None,
+				ReferendumInfo::Approved(e, s, d) => {
+					let new_e = BlockConverter::convert_block_number(e);
+					Some(ReferendumInfo::Approved(new_e, s, d))
+				},
+				ReferendumInfo::Rejected(e, s, d) => {
+					let new_e = BlockConverter::convert_block_number(e);
+					Some(ReferendumInfo::Rejected(new_e, s, d))
+				},
+				ReferendumInfo::Cancelled(e, s, d) => {
+					let new_e = BlockConverter::convert_block_number(e);
+					Some(ReferendumInfo::Cancelled(new_e, s, d))
+				},
+				ReferendumInfo::TimedOut(e, s, d) => {
+					let new_e = BlockConverter::convert_block_number(e);
+					Some(ReferendumInfo::TimedOut(new_e, s, d))
+				},
+			};
+			if let Some(new_value) = maybe_new_value {
+				weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1));
+				log::info!(target: TARGET, "migrating referendum #{:?}", &key);
+				ReferendumInfoFor::<T, I>::insert(key, new_value);
+			} else {
+				weight.saturating_accrue(T::DbWeight::get().reads(1));
+			}
+		});
+
+		weight
+	}
+}
+
 #[cfg(test)]
 pub mod test {
 	use super::*;
-	use crate::mock::{Test as T, *};
+	use crate::{
+		migration::switch_block_number_provider::{
+			migrate_block_number_provider, BlockNumberConversion,
+		},
+		mock::{Test as T, *},
+	};
 	use core::str::FromStr;
 
 	// create referendum status v0.
@@ -185,7 +317,6 @@ pub mod test {
 			deciding: None,
 		}
 	}
-
 	#[test]
 	pub fn referendum_status_v0() {
 		// make sure the bytes of the encoded referendum v0 is decodable.
@@ -214,11 +345,11 @@ pub mod test {
 			// run migration from v0 to v1.
 			v1::MigrateV0ToV1::<T, ()>::on_runtime_upgrade();
 			// fetch and assert migrated into v1 the ongoing referendum.
-			let ongoing_v1 = ReferendumInfoFor::<T, ()>::get(2).unwrap();
+			let ongoing_v1 = v1::ReferendumInfoFor::<T, ()>::get(2).unwrap();
 			// referendum status schema is the same for v0 and v1.
 			assert_eq!(ReferendumInfoOf::<T, ()>::Ongoing(status_v0), ongoing_v1);
 			// fetch and assert migrated into v1 the approved referendum.
-			let approved_v1 = ReferendumInfoFor::<T, ()>::get(5).unwrap();
+			let approved_v1 = v1::ReferendumInfoFor::<T, ()>::get(5).unwrap();
 			assert_eq!(
 				approved_v1,
 				ReferendumInfoOf::<T, ()>::Approved(
@@ -229,4 +360,48 @@ pub mod test {
 			);
 		});
 	}
+
+	#[test]
+	fn migration_v1_to_switch_block_number_provider_works() {
+		ExtBuilder::default().build_and_execute(|| {
+			pub struct MockBlockConverter;
+
+			impl BlockNumberConversion<SystemBlockNumberFor<T>, BlockNumberFor<T, ()>> for MockBlockConverter {
+				fn convert_block_number(block_number: SystemBlockNumberFor<T>) -> BlockNumberFor<T, ()> {
+					block_number as u64 + 10u64
+				}
+			}
+
+			let referendum_ongoing = v1::ReferendumInfoOf::<T, ()>::Ongoing(create_status_v0());
+			let referendum_approved = v1::ReferendumInfoOf::<T, ()>::Approved(
+				50, //old block number
+				Some(Deposit { who: 1, amount: 10 }),
+				Some(Deposit { who: 2, amount: 20 }),
+			);
+
+			ReferendumCount::<T, ()>::mutate(|x| x.saturating_inc());
+			v1::ReferendumInfoFor::<T, ()>::insert(1, referendum_ongoing);
+
+			ReferendumCount::<T, ()>::mutate(|x| x.saturating_inc());
+			v1::ReferendumInfoFor::<T, ()>::insert(2, referendum_approved);
+
+			migrate_block_number_provider::<MockBlockConverter, T, ()>();
+
+			let ongoing_v2 = ReferendumInfoFor::<T, ()>::get(1).unwrap();
+			assert_eq!(
+				ongoing_v2,
+				ReferendumInfoOf::<T, ()>::Ongoing(create_status_v0())
+			);
+
+			let approved_v2 = ReferendumInfoFor::<T, ()>::get(2).unwrap();
+			assert_eq!(
+				approved_v2,
+				ReferendumInfoOf::<T, ()>::Approved(
+					50,
+					Some(Deposit { who: 1, amount: 10 }),
+					Some(Deposit { who: 2, amount: 20 })
+				)
+			);
+		});
+	}
 }
diff --git a/substrate/frame/referenda/src/mock.rs b/substrate/frame/referenda/src/mock.rs
index 5d36ce137d46d2308166ed131cdfb8a464a1c661..c46236586f1f74d81dcab2ad5f6c21f18c700959 100644
--- a/substrate/frame/referenda/src/mock.rs
+++ b/substrate/frame/referenda/src/mock.rs
@@ -206,6 +206,7 @@ impl Config for Test {
 	type AlarmInterval = AlarmInterval;
 	type Tracks = TestTracksInfo;
 	type Preimages = Preimage;
+	type BlockNumberProvider = System;
 }
 pub struct ExtBuilder {}
 
diff --git a/substrate/frame/referenda/src/types.rs b/substrate/frame/referenda/src/types.rs
index e83f28b472cda7fa3dc6329fd026440ec415874d..e97e7cc8df6d880ddc6aa2631878e715ba97344a 100644
--- a/substrate/frame/referenda/src/types.rs
+++ b/substrate/frame/referenda/src/types.rs
@@ -30,6 +30,10 @@ use sp_runtime::{FixedI64, PerThing, RuntimeDebug};
 
 pub type BalanceOf<T, I = ()> =
 	<<T as Config<I>>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance;
+
+pub type BlockNumberFor<T, I> =
+	<<T as Config<I>>::BlockNumberProvider as BlockNumberProvider>::BlockNumber;
+
 pub type NegativeImbalanceOf<T, I> = <<T as Config<I>>::Currency as Currency<
 	<T as frame_system::Config>::AccountId,
 >>::NegativeImbalance;
@@ -43,7 +47,7 @@ pub type PalletsOriginOf<T> =
 pub type ReferendumInfoOf<T, I> = ReferendumInfo<
 	TrackIdOf<T, I>,
 	PalletsOriginOf<T>,
-	BlockNumberFor<T>,
+	BlockNumberFor<T, I>,
 	BoundedCallOf<T, I>,
 	BalanceOf<T, I>,
 	TallyOf<T, I>,
@@ -53,19 +57,19 @@ pub type ReferendumInfoOf<T, I> = ReferendumInfo<
 pub type ReferendumStatusOf<T, I> = ReferendumStatus<
 	TrackIdOf<T, I>,
 	PalletsOriginOf<T>,
-	BlockNumberFor<T>,
+	BlockNumberFor<T, I>,
 	BoundedCallOf<T, I>,
 	BalanceOf<T, I>,
 	TallyOf<T, I>,
 	<T as frame_system::Config>::AccountId,
 	ScheduleAddressOf<T, I>,
 >;
-pub type DecidingStatusOf<T> = DecidingStatus<BlockNumberFor<T>>;
-pub type TrackInfoOf<T, I = ()> = TrackInfo<BalanceOf<T, I>, BlockNumberFor<T>>;
+pub type DecidingStatusOf<T, I> = DecidingStatus<BlockNumberFor<T, I>>;
+pub type TrackInfoOf<T, I = ()> = TrackInfo<BalanceOf<T, I>, BlockNumberFor<T, I>>;
 pub type TrackIdOf<T, I> =
-	<<T as Config<I>>::Tracks as TracksInfo<BalanceOf<T, I>, BlockNumberFor<T>>>::Id;
+	<<T as Config<I>>::Tracks as TracksInfo<BalanceOf<T, I>, BlockNumberFor<T, I>>>::Id;
 pub type ScheduleAddressOf<T, I> = <<T as Config<I>>::Scheduler as Anon<
-	BlockNumberFor<T>,
+	BlockNumberFor<T, I>,
 	CallOf<T, I>,
 	PalletsOriginOf<T>,
 >>::Address;