diff --git a/substrate/frame/collective/src/lib.rs b/substrate/frame/collective/src/lib.rs
index f904b42af028d54a03d0267144fdb31051fef3d4..fc4ab0c4f1bbd5f50bf08e0b45109bdf36a835e7 100644
--- a/substrate/frame/collective/src/lib.rs
+++ b/substrate/frame/collective/src/lib.rs
@@ -53,9 +53,10 @@ use frame_support::{
 		DispatchError, DispatchResult, DispatchResultWithPostInfo, Dispatchable, GetDispatchInfo,
 		Pays, PostDispatchInfo,
 	},
-	ensure,
+	ensure, impl_ensure_origin_with_arg_ignoring_arg,
 	traits::{
-		Backing, ChangeMembers, EnsureOrigin, Get, GetBacking, InitializeMembers, StorageVersion,
+		Backing, ChangeMembers, EnsureOrigin, EnsureOriginWithArg, Get, GetBacking,
+		InitializeMembers, StorageVersion,
 	},
 	weights::Weight,
 };
@@ -1154,6 +1155,12 @@ impl<
 	}
 }
 
+impl_ensure_origin_with_arg_ignoring_arg! {
+	impl< { O: .., I: 'static, AccountId: Decode, T } >
+		EnsureOriginWithArg<O, T> for EnsureMember<AccountId, I>
+	{}
+}
+
 pub struct EnsureMembers<AccountId, I: 'static, const N: u32>(PhantomData<(AccountId, I)>);
 impl<
 		O: Into<Result<RawOrigin<AccountId, I>, O>> + From<RawOrigin<AccountId, I>>,
@@ -1176,6 +1183,12 @@ impl<
 	}
 }
 
+impl_ensure_origin_with_arg_ignoring_arg! {
+	impl< { O: .., I: 'static, const N: u32, AccountId, T } >
+		EnsureOriginWithArg<O, T> for EnsureMembers<AccountId, I, N>
+	{}
+}
+
 pub struct EnsureProportionMoreThan<AccountId, I: 'static, const N: u32, const D: u32>(
 	PhantomData<(AccountId, I)>,
 );
@@ -1201,6 +1214,12 @@ impl<
 	}
 }
 
+impl_ensure_origin_with_arg_ignoring_arg! {
+	impl< { O: .., I: 'static, const N: u32, const D: u32, AccountId, T } >
+		EnsureOriginWithArg<O, T> for EnsureProportionMoreThan<AccountId, I, N, D>
+	{}
+}
+
 pub struct EnsureProportionAtLeast<AccountId, I: 'static, const N: u32, const D: u32>(
 	PhantomData<(AccountId, I)>,
 );
@@ -1225,3 +1244,9 @@ impl<
 		Ok(O::from(RawOrigin::Members(0u32, 0u32)))
 	}
 }
+
+impl_ensure_origin_with_arg_ignoring_arg! {
+	impl< { O: .., I: 'static, const N: u32, const D: u32, AccountId, T } >
+		EnsureOriginWithArg<O, T> for EnsureProportionAtLeast<AccountId, I, N, D>
+	{}
+}
diff --git a/substrate/frame/core-fellowship/src/lib.rs b/substrate/frame/core-fellowship/src/lib.rs
index 9ca13db1726382cd90316348133f8558f6f3c1df..ba02627ec11b9213afb81972e5a5478c9c807c8c 100644
--- a/substrate/frame/core-fellowship/src/lib.rs
+++ b/substrate/frame/core-fellowship/src/lib.rs
@@ -65,8 +65,10 @@ use sp_std::{marker::PhantomData, prelude::*};
 
 use frame_support::{
 	dispatch::DispatchResultWithPostInfo,
-	ensure,
-	traits::{tokens::Balance as BalanceTrait, EnsureOrigin, Get, RankedMembers},
+	ensure, impl_ensure_origin_with_arg_ignoring_arg,
+	traits::{
+		tokens::Balance as BalanceTrait, EnsureOrigin, EnsureOriginWithArg, Get, RankedMembers,
+	},
 	BoundedVec, RuntimeDebug,
 };
 
@@ -570,7 +572,7 @@ impl<T: Config<I>, I: 'static, const MIN_RANK: u16> EnsureOrigin<T::RuntimeOrigi
 	type Success = T::AccountId;
 
 	fn try_origin(o: T::RuntimeOrigin) -> Result<Self::Success, T::RuntimeOrigin> {
-		let who = frame_system::EnsureSigned::try_origin(o)?;
+		let who = <frame_system::EnsureSigned<_> as EnsureOrigin<_>>::try_origin(o)?;
 		match T::Members::rank_of(&who) {
 			Some(rank) if rank >= MIN_RANK && Member::<T, I>::contains_key(&who) => Ok(who),
 			_ => Err(frame_system::RawOrigin::Signed(who).into()),
@@ -591,3 +593,9 @@ impl<T: Config<I>, I: 'static, const MIN_RANK: u16> EnsureOrigin<T::RuntimeOrigi
 		Ok(frame_system::RawOrigin::Signed(who).into())
 	}
 }
+
+impl_ensure_origin_with_arg_ignoring_arg! {
+	impl< { T: Config<I>, I: 'static, const MIN_RANK: u16, A } >
+		EnsureOriginWithArg<T::RuntimeOrigin, A> for EnsureInducted<T, I, MIN_RANK>
+	{}
+}
diff --git a/substrate/frame/ranked-collective/src/lib.rs b/substrate/frame/ranked-collective/src/lib.rs
index 6296403d2a1ce04ce6239b8574165f85b0383718..6fe9fc221a7df3cd04036dc7d4270014e2047d85 100644
--- a/substrate/frame/ranked-collective/src/lib.rs
+++ b/substrate/frame/ranked-collective/src/lib.rs
@@ -53,8 +53,8 @@ use sp_std::{marker::PhantomData, prelude::*};
 use frame_support::{
 	codec::{Decode, Encode, MaxEncodedLen},
 	dispatch::{DispatchError, DispatchResultWithPostInfo, PostDispatchInfo},
-	ensure,
-	traits::{EnsureOrigin, PollStatus, Polling, RankedMembers, VoteTally},
+	ensure, impl_ensure_origin_with_arg_ignoring_arg,
+	traits::{EnsureOrigin, EnsureOriginWithArg, PollStatus, Polling, RankedMembers, VoteTally},
 	CloneNoBound, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound,
 };
 
@@ -263,7 +263,7 @@ impl<T: Config<I>, I: 'static, const MIN_RANK: u16> EnsureOrigin<T::RuntimeOrigi
 	type Success = Rank;
 
 	fn try_origin(o: T::RuntimeOrigin) -> Result<Self::Success, T::RuntimeOrigin> {
-		let who = frame_system::EnsureSigned::try_origin(o)?;
+		let who = <frame_system::EnsureSigned<_> as EnsureOrigin<_>>::try_origin(o)?;
 		match Members::<T, I>::get(&who) {
 			Some(MemberRecord { rank, .. }) if rank >= MIN_RANK => Ok(rank),
 			_ => Err(frame_system::RawOrigin::Signed(who).into()),
@@ -272,7 +272,36 @@ impl<T: Config<I>, I: 'static, const MIN_RANK: u16> EnsureOrigin<T::RuntimeOrigi
 
 	#[cfg(feature = "runtime-benchmarks")]
 	fn try_successful_origin() -> Result<T::RuntimeOrigin, ()> {
-		EnsureRankedMember::<T, I, MIN_RANK>::try_successful_origin()
+		<EnsureRankedMember<T, I, MIN_RANK> as EnsureOrigin<_>>::try_successful_origin()
+	}
+}
+
+impl_ensure_origin_with_arg_ignoring_arg! {
+	impl<{ T: Config<I>, I: 'static, const MIN_RANK: u16, A }>
+		EnsureOriginWithArg<T::RuntimeOrigin, A> for EnsureRanked<T, I, MIN_RANK>
+	{}
+}
+
+/// Guard to ensure that the given origin is a member of the collective. The rank of the member is
+/// the `Success` value.
+pub struct EnsureOfRank<T, I>(PhantomData<(T, I)>);
+impl<T: Config<I>, I: 'static> EnsureOriginWithArg<T::RuntimeOrigin, Rank> for EnsureOfRank<T, I> {
+	type Success = (T::AccountId, Rank);
+
+	fn try_origin(o: T::RuntimeOrigin, min_rank: &Rank) -> Result<Self::Success, T::RuntimeOrigin> {
+		let who = <frame_system::EnsureSigned<_> as EnsureOrigin<_>>::try_origin(o)?;
+		match Members::<T, I>::get(&who) {
+			Some(MemberRecord { rank, .. }) if rank >= *min_rank => Ok((who, rank)),
+			_ => Err(frame_system::RawOrigin::Signed(who).into()),
+		}
+	}
+
+	#[cfg(feature = "runtime-benchmarks")]
+	fn try_successful_origin(min_rank: &Rank) -> Result<T::RuntimeOrigin, ()> {
+		let who = frame_benchmarking::account::<T::AccountId>("successful_origin", 0, 0);
+		crate::Pallet::<T, I>::do_add_member_to_rank(who.clone(), *min_rank)
+			.expect("Could not add members for benchmarks");
+		Ok(frame_system::RawOrigin::Signed(who).into())
 	}
 }
 
@@ -285,7 +314,7 @@ impl<T: Config<I>, I: 'static, const MIN_RANK: u16> EnsureOrigin<T::RuntimeOrigi
 	type Success = T::AccountId;
 
 	fn try_origin(o: T::RuntimeOrigin) -> Result<Self::Success, T::RuntimeOrigin> {
-		let who = frame_system::EnsureSigned::try_origin(o)?;
+		let who = <frame_system::EnsureSigned<_> as EnsureOrigin<_>>::try_origin(o)?;
 		match Members::<T, I>::get(&who) {
 			Some(MemberRecord { rank, .. }) if rank >= MIN_RANK => Ok(who),
 			_ => Err(frame_system::RawOrigin::Signed(who).into()),
@@ -294,10 +323,16 @@ impl<T: Config<I>, I: 'static, const MIN_RANK: u16> EnsureOrigin<T::RuntimeOrigi
 
 	#[cfg(feature = "runtime-benchmarks")]
 	fn try_successful_origin() -> Result<T::RuntimeOrigin, ()> {
-		EnsureRankedMember::<T, I, MIN_RANK>::try_successful_origin()
+		<EnsureRankedMember<T, I, MIN_RANK> as EnsureOrigin<_>>::try_successful_origin()
 	}
 }
 
+impl_ensure_origin_with_arg_ignoring_arg! {
+	impl<{ T: Config<I>, I: 'static, const MIN_RANK: u16, A }>
+		EnsureOriginWithArg<T::RuntimeOrigin, A> for EnsureMember<T, I, MIN_RANK>
+	{}
+}
+
 /// Guard to ensure that the given origin is a member of the collective. The pair of both the
 /// account ID and the rank of the member is the `Success` value.
 pub struct EnsureRankedMember<T, I, const MIN_RANK: u16>(PhantomData<(T, I)>);
@@ -307,7 +342,7 @@ impl<T: Config<I>, I: 'static, const MIN_RANK: u16> EnsureOrigin<T::RuntimeOrigi
 	type Success = (T::AccountId, Rank);
 
 	fn try_origin(o: T::RuntimeOrigin) -> Result<Self::Success, T::RuntimeOrigin> {
-		let who = frame_system::EnsureSigned::try_origin(o)?;
+		let who = <frame_system::EnsureSigned<_> as EnsureOrigin<_>>::try_origin(o)?;
 		match Members::<T, I>::get(&who) {
 			Some(MemberRecord { rank, .. }) if rank >= MIN_RANK => Ok((who, rank)),
 			_ => Err(frame_system::RawOrigin::Signed(who).into()),
@@ -323,6 +358,12 @@ impl<T: Config<I>, I: 'static, const MIN_RANK: u16> EnsureOrigin<T::RuntimeOrigi
 	}
 }
 
+impl_ensure_origin_with_arg_ignoring_arg! {
+	impl<{ T: Config<I>, I: 'static, const MIN_RANK: u16, A }>
+		EnsureOriginWithArg<T::RuntimeOrigin, A> for EnsureRankedMember<T, I, MIN_RANK>
+	{}
+}
+
 #[frame_support::pallet]
 pub mod pallet {
 	use super::*;
@@ -708,6 +749,15 @@ pub mod pallet {
 			}
 			Ok(())
 		}
+
+		/// Determine the rank of the account behind the `Signed` origin `o`, `None` if the account
+		/// is unknown to this collective or `o` is not `Signed`.
+		pub fn as_rank(
+			o: &<T::RuntimeOrigin as frame_support::traits::OriginTrait>::PalletsOrigin,
+		) -> Option<u16> {
+			use frame_support::traits::CallerTrait;
+			o.as_signed().and_then(Self::rank_of)
+		}
 	}
 
 	impl<T: Config<I>, I: 'static> RankedMembers for Pallet<T, I> {
diff --git a/substrate/frame/ranked-collective/src/tests.rs b/substrate/frame/ranked-collective/src/tests.rs
index 04519bc0f8e2247a62b59842a0acbb32cd3fe31f..338dcaacedcf74fd9352e125bd30d6897cda4029 100644
--- a/substrate/frame/ranked-collective/src/tests.rs
+++ b/substrate/frame/ranked-collective/src/tests.rs
@@ -464,34 +464,52 @@ fn ensure_ranked_works() {
 		type Rank2 = EnsureRanked<Test, (), 2>;
 		type Rank3 = EnsureRanked<Test, (), 3>;
 		type Rank4 = EnsureRanked<Test, (), 4>;
-		assert_eq!(Rank1::try_origin(RuntimeOrigin::signed(1)).unwrap(), 1);
-		assert_eq!(Rank1::try_origin(RuntimeOrigin::signed(2)).unwrap(), 2);
-		assert_eq!(Rank1::try_origin(RuntimeOrigin::signed(3)).unwrap(), 3);
+		assert_eq!(<Rank1 as EnsureOrigin<_>>::try_origin(RuntimeOrigin::signed(1)).unwrap(), 1);
+		assert_eq!(<Rank1 as EnsureOrigin<_>>::try_origin(RuntimeOrigin::signed(2)).unwrap(), 2);
+		assert_eq!(<Rank1 as EnsureOrigin<_>>::try_origin(RuntimeOrigin::signed(3)).unwrap(), 3);
 		assert_eq!(
-			Rank2::try_origin(RuntimeOrigin::signed(1)).unwrap_err().as_signed().unwrap(),
+			<Rank2 as EnsureOrigin<_>>::try_origin(RuntimeOrigin::signed(1))
+				.unwrap_err()
+				.into_signer()
+				.unwrap(),
 			1
 		);
-		assert_eq!(Rank2::try_origin(RuntimeOrigin::signed(2)).unwrap(), 2);
-		assert_eq!(Rank2::try_origin(RuntimeOrigin::signed(3)).unwrap(), 3);
+		assert_eq!(<Rank2 as EnsureOrigin<_>>::try_origin(RuntimeOrigin::signed(2)).unwrap(), 2);
+		assert_eq!(<Rank2 as EnsureOrigin<_>>::try_origin(RuntimeOrigin::signed(3)).unwrap(), 3);
 		assert_eq!(
-			Rank3::try_origin(RuntimeOrigin::signed(1)).unwrap_err().as_signed().unwrap(),
+			<Rank3 as EnsureOrigin<_>>::try_origin(RuntimeOrigin::signed(1))
+				.unwrap_err()
+				.into_signer()
+				.unwrap(),
 			1
 		);
 		assert_eq!(
-			Rank3::try_origin(RuntimeOrigin::signed(2)).unwrap_err().as_signed().unwrap(),
+			<Rank3 as EnsureOrigin<_>>::try_origin(RuntimeOrigin::signed(2))
+				.unwrap_err()
+				.into_signer()
+				.unwrap(),
 			2
 		);
-		assert_eq!(Rank3::try_origin(RuntimeOrigin::signed(3)).unwrap(), 3);
+		assert_eq!(<Rank3 as EnsureOrigin<_>>::try_origin(RuntimeOrigin::signed(3)).unwrap(), 3);
 		assert_eq!(
-			Rank4::try_origin(RuntimeOrigin::signed(1)).unwrap_err().as_signed().unwrap(),
+			<Rank4 as EnsureOrigin<_>>::try_origin(RuntimeOrigin::signed(1))
+				.unwrap_err()
+				.into_signer()
+				.unwrap(),
 			1
 		);
 		assert_eq!(
-			Rank4::try_origin(RuntimeOrigin::signed(2)).unwrap_err().as_signed().unwrap(),
+			<Rank4 as EnsureOrigin<_>>::try_origin(RuntimeOrigin::signed(2))
+				.unwrap_err()
+				.into_signer()
+				.unwrap(),
 			2
 		);
 		assert_eq!(
-			Rank4::try_origin(RuntimeOrigin::signed(3)).unwrap_err().as_signed().unwrap(),
+			<Rank4 as EnsureOrigin<_>>::try_origin(RuntimeOrigin::signed(3))
+				.unwrap_err()
+				.into_signer()
+				.unwrap(),
 			3
 		);
 	});
diff --git a/substrate/frame/referenda/src/benchmarking.rs b/substrate/frame/referenda/src/benchmarking.rs
index 288c65feae5679e7399a0b1623172f9e507ed6c5..4c332a3048d0bf08adbc80bada5fe0f1d5b2e6ad 100644
--- a/substrate/frame/referenda/src/benchmarking.rs
+++ b/substrate/frame/referenda/src/benchmarking.rs
@@ -26,7 +26,7 @@ use frame_benchmarking::v1::{
 use frame_support::{
 	assert_ok,
 	dispatch::UnfilteredDispatchable,
-	traits::{Bounded, Currency, EnsureOrigin},
+	traits::{Bounded, Currency, EnsureOrigin, EnsureOriginWithArg},
 };
 use frame_system::RawOrigin;
 use sp_runtime::traits::Bounded as ArithBounded;
@@ -196,7 +196,7 @@ fn is_not_confirming<T: Config<I>, I: 'static>(index: ReferendumIndex) -> bool {
 benchmarks_instance_pallet! {
 	submit {
 		let origin =
-			T::SubmitOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;
+			T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into()).map_err(|_| BenchmarkError::Weightless)?;
 		if let Ok(caller) = frame_system::ensure_signed(origin.clone()) {
 			T::Currency::make_free_balance_be(&caller, BalanceOf::<T, I>::max_value());
 			whitelist_account!(caller);
@@ -213,7 +213,7 @@ benchmarks_instance_pallet! {
 
 	place_decision_deposit_preparing {
 		let origin =
-			T::SubmitOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;
+			T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into()).map_err(|_| BenchmarkError::Weightless)?;
 		let index = create_referendum::<T, I>(origin.clone());
 	}: place_decision_deposit<T::RuntimeOrigin>(origin, index)
 	verify {
@@ -222,7 +222,7 @@ benchmarks_instance_pallet! {
 
 	place_decision_deposit_queued {
 		let origin =
-			T::SubmitOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;
+			T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into()).map_err(|_| BenchmarkError::Weightless)?;
 		let index = create_referendum::<T, I>(origin.clone());
 		fill_queue::<T, I>(origin.clone(), index, 1, 90);
 	}: place_decision_deposit<T::RuntimeOrigin>(origin, index)
@@ -234,7 +234,7 @@ benchmarks_instance_pallet! {
 
 	place_decision_deposit_not_queued {
 		let origin =
-			T::SubmitOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;
+			T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into()).map_err(|_| BenchmarkError::Weightless)?;
 		let index = create_referendum::<T, I>(origin.clone());
 		fill_queue::<T, I>(origin.clone(), index, 0, 90);
 		let track = Referenda::<T, I>::ensure_ongoing(index).unwrap().track;
@@ -248,7 +248,7 @@ benchmarks_instance_pallet! {
 
 	place_decision_deposit_passing {
 		let origin =
-			T::SubmitOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;
+			T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into()).map_err(|_| BenchmarkError::Weightless)?;
 		let index = create_referendum::<T, I>(origin.clone());
 		skip_prepare_period::<T, I>(index);
 		make_passing::<T, I>(index);
@@ -259,7 +259,7 @@ benchmarks_instance_pallet! {
 
 	place_decision_deposit_failing {
 		let origin =
-			T::SubmitOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;
+			T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into()).map_err(|_| BenchmarkError::Weightless)?;
 		let index = create_referendum::<T, I>(origin.clone());
 		skip_prepare_period::<T, I>(index);
 	}: place_decision_deposit<T::RuntimeOrigin>(origin, index)
@@ -269,7 +269,7 @@ benchmarks_instance_pallet! {
 
 	refund_decision_deposit {
 		let origin =
-			T::SubmitOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;
+			T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into()).map_err(|_| BenchmarkError::Weightless)?;
 		let index = create_referendum::<T, I>(origin.clone());
 		place_deposit::<T, I>(index);
 		assert_ok!(Referenda::<T, I>::cancel(
@@ -284,7 +284,7 @@ benchmarks_instance_pallet! {
 
 	refund_submission_deposit {
 		let origin =
-			T::SubmitOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;
+			T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into()).map_err(|_| BenchmarkError::Weightless)?;
 		let index = create_referendum::<T, I>(origin.clone());
 		let caller = frame_system::ensure_signed(origin.clone()).unwrap();
 		let balance = T::Currency::free_balance(&caller);
@@ -303,7 +303,7 @@ benchmarks_instance_pallet! {
 	}
 
 	cancel {
-		let origin = T::SubmitOrigin::try_successful_origin()
+		let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into())
 			.expect("SubmitOrigin has no successful origin required for the benchmark");
 		let index = create_referendum::<T, I>(origin);
 		place_deposit::<T, I>(index);
@@ -315,7 +315,7 @@ benchmarks_instance_pallet! {
 	}
 
 	kill {
-		let origin = T::SubmitOrigin::try_successful_origin()
+		let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into())
 			.expect("SubmitOrigin has no successful origin required for the benchmark");
 		let index = create_referendum::<T, I>(origin);
 		place_deposit::<T, I>(index);
@@ -327,7 +327,7 @@ benchmarks_instance_pallet! {
 	}
 
 	one_fewer_deciding_queue_empty {
-		let origin = T::SubmitOrigin::try_successful_origin()
+		let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into())
 			.expect("SubmitOrigin has no successful origin required for the benchmark");
 		let index = create_referendum::<T, I>(origin);
 		place_deposit::<T, I>(index);
@@ -346,7 +346,7 @@ benchmarks_instance_pallet! {
 	}
 
 	one_fewer_deciding_failing {
-		let origin = T::SubmitOrigin::try_successful_origin()
+		let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into())
 			.expect("SubmitOrigin has no successful origin required for the benchmark");
 		let index = create_referendum::<T, I>(origin.clone());
 		// No spaces free in the queue.
@@ -371,7 +371,7 @@ benchmarks_instance_pallet! {
 	}
 
 	one_fewer_deciding_passing {
-		let origin = T::SubmitOrigin::try_successful_origin()
+		let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into())
 			.expect("SubmitOrigin has no successful origin required for the benchmark");
 		let index = create_referendum::<T, I>(origin.clone());
 		// No spaces free in the queue.
@@ -396,7 +396,7 @@ benchmarks_instance_pallet! {
 	}
 
 	nudge_referendum_requeued_insertion {
-		let origin = T::SubmitOrigin::try_successful_origin()
+		let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into())
 			.expect("SubmitOrigin has no successful origin required for the benchmark");
 		// First create our referendum and place the deposit. It will be failing.
 		let index = create_referendum::<T, I>(origin.clone());
@@ -419,7 +419,7 @@ benchmarks_instance_pallet! {
 	}
 
 	nudge_referendum_requeued_slide {
-		let origin = T::SubmitOrigin::try_successful_origin()
+		let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into())
 			.expect("SubmitOrigin has no successful origin required for the benchmark");
 		// First create our referendum and place the deposit. It will be failing.
 		let index = create_referendum::<T, I>(origin.clone());
@@ -447,7 +447,7 @@ benchmarks_instance_pallet! {
 		// free and this failing. It would result in `QUEUE_SIZE - 1` items being shifted for the
 		// insertion at the beginning.
 
-		let origin = T::SubmitOrigin::try_successful_origin()
+		let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into())
 			.expect("SubmitOrigin has no successful origin required for the benchmark");
 		// First create our referendum and place the deposit. It will be failing.
 		let index = create_referendum::<T, I>(origin.clone());
@@ -466,7 +466,7 @@ benchmarks_instance_pallet! {
 	}
 
 	nudge_referendum_not_queued {
-		let origin = T::SubmitOrigin::try_successful_origin()
+		let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into())
 			.expect("SubmitOrigin has no successful origin required for the benchmark");
 		// First create our referendum and place the deposit. It will be failing.
 		let index = create_referendum::<T, I>(origin.clone());
@@ -485,7 +485,7 @@ benchmarks_instance_pallet! {
 	}
 
 	nudge_referendum_no_deposit {
-		let origin = T::SubmitOrigin::try_successful_origin()
+		let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into())
 			.expect("SubmitOrigin has no successful origin required for the benchmark");
 		let index = create_referendum::<T, I>(origin);
 		skip_prepare_period::<T, I>(index);
@@ -496,7 +496,7 @@ benchmarks_instance_pallet! {
 	}
 
 	nudge_referendum_preparing {
-		let origin = T::SubmitOrigin::try_successful_origin()
+		let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into())
 			.expect("SubmitOrigin has no successful origin required for the benchmark");
 		let index = create_referendum::<T, I>(origin);
 		place_deposit::<T, I>(index);
@@ -507,7 +507,7 @@ benchmarks_instance_pallet! {
 	}
 
 	nudge_referendum_timed_out {
-		let origin = T::SubmitOrigin::try_successful_origin()
+		let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into())
 			.expect("SubmitOrigin has no successful origin required for the benchmark");
 		let index = create_referendum::<T, I>(origin);
 		skip_timeout_period::<T, I>(index);
@@ -518,7 +518,7 @@ benchmarks_instance_pallet! {
 	}
 
 	nudge_referendum_begin_deciding_failing {
-		let origin = T::SubmitOrigin::try_successful_origin()
+		let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into())
 			.expect("SubmitOrigin has no successful origin required for the benchmark");
 		let index = create_referendum::<T, I>(origin);
 		place_deposit::<T, I>(index);
@@ -529,7 +529,7 @@ benchmarks_instance_pallet! {
 	}
 
 	nudge_referendum_begin_deciding_passing {
-		let origin = T::SubmitOrigin::try_successful_origin()
+		let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into())
 			.expect("SubmitOrigin has no successful origin required for the benchmark");
 		let index = create_referendum::<T, I>(origin);
 		place_deposit::<T, I>(index);
@@ -541,7 +541,7 @@ benchmarks_instance_pallet! {
 	}
 
 	nudge_referendum_begin_confirming {
-		let origin = T::SubmitOrigin::try_successful_origin()
+		let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into())
 			.expect("SubmitOrigin has no successful origin required for the benchmark");
 		let index = create_referendum::<T, I>(origin);
 		place_deposit::<T, I>(index);
@@ -555,7 +555,7 @@ benchmarks_instance_pallet! {
 	}
 
 	nudge_referendum_end_confirming {
-		let origin = T::SubmitOrigin::try_successful_origin()
+		let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into())
 			.expect("SubmitOrigin has no successful origin required for the benchmark");
 		let index = create_referendum::<T, I>(origin);
 		place_deposit::<T, I>(index);
@@ -570,7 +570,7 @@ benchmarks_instance_pallet! {
 	}
 
 	nudge_referendum_continue_not_confirming {
-		let origin = T::SubmitOrigin::try_successful_origin()
+		let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into())
 			.expect("SubmitOrigin has no successful origin required for the benchmark");
 		let index = create_referendum::<T, I>(origin);
 		place_deposit::<T, I>(index);
@@ -586,7 +586,7 @@ benchmarks_instance_pallet! {
 	}
 
 	nudge_referendum_continue_confirming {
-		let origin = T::SubmitOrigin::try_successful_origin()
+		let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into())
 			.expect("SubmitOrigin has no successful origin required for the benchmark");
 		let index = create_referendum::<T, I>(origin);
 		place_deposit::<T, I>(index);
@@ -601,7 +601,7 @@ benchmarks_instance_pallet! {
 	}
 
 	nudge_referendum_approved {
-		let origin = T::SubmitOrigin::try_successful_origin()
+		let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into())
 			.expect("SubmitOrigin has no successful origin required for the benchmark");
 		let index = create_referendum::<T, I>(origin);
 		place_deposit::<T, I>(index);
@@ -616,7 +616,7 @@ benchmarks_instance_pallet! {
 	}
 
 	nudge_referendum_rejected {
-		let origin = T::SubmitOrigin::try_successful_origin()
+		let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into())
 			.expect("SubmitOrigin has no successful origin required for the benchmark");
 		let index = create_referendum::<T, I>(origin);
 		place_deposit::<T, I>(index);
@@ -632,7 +632,7 @@ benchmarks_instance_pallet! {
 
 	set_some_metadata {
 		use sp_std::borrow::Cow;
-		let origin = T::SubmitOrigin::try_successful_origin()
+		let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into())
 			.expect("SubmitOrigin has no successful origin required for the benchmark");
 		let index = create_referendum::<T, I>(origin.clone());
 		let hash = T::Preimages::note(Cow::from(vec![5, 6])).unwrap();
@@ -643,7 +643,7 @@ benchmarks_instance_pallet! {
 
 	clear_metadata {
 		use sp_std::borrow::Cow;
-		let origin = T::SubmitOrigin::try_successful_origin()
+		let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into())
 			.expect("SubmitOrigin has no successful origin required for the benchmark");
 		let index = create_referendum::<T, I>(origin.clone());
 		let hash = T::Preimages::note(Cow::from(vec![6, 7, 8])).unwrap();
diff --git a/substrate/frame/referenda/src/lib.rs b/substrate/frame/referenda/src/lib.rs
index dd352d0af40cbceb4b62544ba3129b41927e2917..3756257c33fe524761578e327bea3006134afee3 100644
--- a/substrate/frame/referenda/src/lib.rs
+++ b/substrate/frame/referenda/src/lib.rs
@@ -138,7 +138,7 @@ const ASSEMBLY_ID: LockIdentifier = *b"assembly";
 #[frame_support::pallet]
 pub mod pallet {
 	use super::*;
-	use frame_support::pallet_prelude::*;
+	use frame_support::{pallet_prelude::*, traits::EnsureOriginWithArg};
 	use frame_system::pallet_prelude::*;
 
 	/// The current storage version.
@@ -167,7 +167,11 @@ pub mod pallet {
 		type Currency: ReservableCurrency<Self::AccountId>;
 		// Origins and unbalances.
 		/// Origin from which proposals may be submitted.
-		type SubmitOrigin: EnsureOrigin<Self::RuntimeOrigin, Success = Self::AccountId>;
+		type SubmitOrigin: EnsureOriginWithArg<
+			Self::RuntimeOrigin,
+			PalletsOriginOf<Self>,
+			Success = Self::AccountId,
+		>;
 		/// Origin from which any vote may be cancelled.
 		type CancelOrigin: EnsureOrigin<Self::RuntimeOrigin>;
 		/// Origin from which any vote may be killed.
@@ -430,7 +434,8 @@ pub mod pallet {
 			proposal: BoundedCallOf<T, I>,
 			enactment_moment: DispatchTime<T::BlockNumber>,
 		) -> DispatchResult {
-			let who = T::SubmitOrigin::ensure_origin(origin)?;
+			let proposal_origin = *proposal_origin;
+			let who = T::SubmitOrigin::ensure_origin(origin, &proposal_origin)?;
 
 			let track =
 				T::Tracks::track_for(&proposal_origin).map_err(|_| Error::<T, I>::NoTrack)?;
@@ -445,7 +450,7 @@ pub mod pallet {
 				T::Preimages::bound(CallOf::<T, I>::from(Call::nudge_referendum { index }))?;
 			let status = ReferendumStatus {
 				track,
-				origin: *proposal_origin,
+				origin: proposal_origin,
 				proposal: proposal.clone(),
 				enactment: enactment_moment,
 				submitted: now,
diff --git a/substrate/frame/society/src/lib.rs b/substrate/frame/society/src/lib.rs
index d92bee48d6aa5d4e77e468fdf10fd510b122856a..4ac853ce8e89a5f4c1e379192dba2ba662421dea 100644
--- a/substrate/frame/society/src/lib.rs
+++ b/substrate/frame/society/src/lib.rs
@@ -252,10 +252,11 @@ mod mock;
 mod tests;
 
 use frame_support::{
+	impl_ensure_origin_with_arg_ignoring_arg,
 	pallet_prelude::*,
 	traits::{
-		BalanceStatus, ChangeMembers, Currency, EnsureOrigin, ExistenceRequirement::AllowDeath,
-		Imbalance, OnUnbalanced, Randomness, ReservableCurrency,
+		BalanceStatus, ChangeMembers, Currency, EnsureOrigin, EnsureOriginWithArg,
+		ExistenceRequirement::AllowDeath, Imbalance, OnUnbalanced, Randomness, ReservableCurrency,
 	},
 	PalletId,
 };
@@ -1181,6 +1182,12 @@ impl<T: Config> EnsureOrigin<T::RuntimeOrigin> for EnsureFounder<T> {
 	}
 }
 
+impl_ensure_origin_with_arg_ignoring_arg! {
+	impl<{ T: Config, A }>
+		EnsureOriginWithArg<T::RuntimeOrigin, A> for EnsureFounder<T>
+	{}
+}
+
 /// Pick an item at pseudo-random from the slice, given the `rng`. `None` iff the slice is empty.
 fn pick_item<'a, R: RngCore, T>(rng: &mut R, items: &'a [T]) -> Option<&'a T> {
 	if items.is_empty() {
diff --git a/substrate/frame/support/procedural/src/construct_runtime/expand/origin.rs b/substrate/frame/support/procedural/src/construct_runtime/expand/origin.rs
index e48a70a9df97314d366fb8894ce69121c4707ba6..0eaa73f603068fab4b9ef9b592b44bf6219081ca 100644
--- a/substrate/frame/support/procedural/src/construct_runtime/expand/origin.rs
+++ b/substrate/frame/support/procedural/src/construct_runtime/expand/origin.rs
@@ -418,6 +418,34 @@ fn expand_origin_pallet_conversions(
 				}
 			}
 		}
+
+		#attr
+		impl<'a> TryFrom<&'a OriginCaller> for &'a #pallet_origin {
+			type Error = ();
+			fn try_from(
+				x: &'a OriginCaller,
+			) -> #scrate::sp_std::result::Result<&'a #pallet_origin, ()> {
+				if let OriginCaller::#variant_name(l) = x {
+					Ok(&l)
+				} else {
+					Err(())
+				}
+			}
+		}
+
+		#attr
+		impl<'a> TryFrom<&'a RuntimeOrigin> for &'a #pallet_origin {
+			type Error = ();
+			fn try_from(
+				x: &'a RuntimeOrigin,
+			) -> #scrate::sp_std::result::Result<&'a #pallet_origin, ()> {
+				if let OriginCaller::#variant_name(l) = &x.caller {
+					Ok(&l)
+				} else {
+					Err(())
+				}
+			}
+		}
 	}
 }
 
diff --git a/substrate/frame/support/src/dispatch.rs b/substrate/frame/support/src/dispatch.rs
index 47c7b22f5bf158e5cb29a034c68a265a06229972..8164b8361af87efa06b82268560bd84f104539e5 100644
--- a/substrate/frame/support/src/dispatch.rs
+++ b/substrate/frame/support/src/dispatch.rs
@@ -89,6 +89,26 @@ impl<AccountId> From<Option<AccountId>> for RawOrigin<AccountId> {
 	}
 }
 
+impl<AccountId> RawOrigin<AccountId> {
+	/// Returns `Some` with a reference to the `AccountId` if `self` is `Signed`, `None` otherwise.
+	pub fn as_signed(&self) -> Option<&AccountId> {
+		match &self {
+			Self::Signed(x) => Some(x),
+			_ => None,
+		}
+	}
+
+	/// Returns `true` if `self` is `Root`, `None` otherwise.
+	pub fn is_root(&self) -> bool {
+		matches!(&self, Self::Root)
+	}
+
+	/// Returns `true` if `self` is `None`, `None` otherwise.
+	pub fn is_none(&self) -> bool {
+		matches!(&self, Self::None)
+	}
+}
+
 /// A type that can be used as a parameter in a dispatchable function.
 ///
 /// When using `decl_module` all arguments for call functions must implement this trait.
diff --git a/substrate/frame/support/src/traits.rs b/substrate/frame/support/src/traits.rs
index 3db274c1720c67efec0f86e98cd5d0df1941af07..e4fd04750441a7781e4352fe2b5ed8ecb9b246c6 100644
--- a/substrate/frame/support/src/traits.rs
+++ b/substrate/frame/support/src/traits.rs
@@ -98,7 +98,7 @@ pub use dispatch::EnsureOneOf;
 pub use dispatch::{
 	AsEnsureOriginWithArg, CallerTrait, EitherOf, EitherOfDiverse, EnsureOrigin,
 	EnsureOriginEqualOrHigherPrivilege, EnsureOriginWithArg, MapSuccess, NeverEnsureOrigin,
-	OriginTrait, TryMapSuccess, UnfilteredDispatchable,
+	OriginTrait, TryMapSuccess, TryWithMorphedArg, UnfilteredDispatchable,
 };
 
 mod voting;
diff --git a/substrate/frame/support/src/traits/dispatch.rs b/substrate/frame/support/src/traits/dispatch.rs
index 6961e69ba5750de94c1505823d39a538b7421e8f..9ea58479a0dfee384d1fb34c23e7d47947c5ffb4 100644
--- a/substrate/frame/support/src/traits/dispatch.rs
+++ b/substrate/frame/support/src/traits/dispatch.rs
@@ -48,19 +48,6 @@ pub trait EnsureOrigin<OuterOrigin> {
 	fn try_successful_origin() -> Result<OuterOrigin, ()>;
 }
 
-/// [`EnsureOrigin`] implementation that always fails.
-pub struct NeverEnsureOrigin<Success>(sp_std::marker::PhantomData<Success>);
-impl<OO, Success> EnsureOrigin<OO> for NeverEnsureOrigin<Success> {
-	type Success = Success;
-	fn try_origin(o: OO) -> Result<Success, OO> {
-		Err(o)
-	}
-	#[cfg(feature = "runtime-benchmarks")]
-	fn try_successful_origin() -> Result<OO, ()> {
-		Err(())
-	}
-}
-
 /// [`EnsureOrigin`] implementation that checks that an origin has equal or higher privilege
 /// compared to the expected `Origin`.
 ///
@@ -166,6 +153,62 @@ pub trait EnsureOriginWithArg<OuterOrigin, Argument> {
 	fn try_successful_origin(a: &Argument) -> Result<OuterOrigin, ()>;
 }
 
+/// Simple macro to explicitly implement [EnsureOriginWithArg] to be used on any type which
+/// implements [EnsureOrigin]. This is quick and dirty, so you must use the type parameters `O`
+/// (the origin type), `T` (the argument type) and `AccountId` (if you are using the `O: ..` form).
+///
+/// The argument is ignored, much like in [AsEnsureOriginWithArg].
+#[macro_export]
+macro_rules! impl_ensure_origin_with_arg_ignoring_arg {
+	( impl < { O: .., I: 'static, $( $bound:tt )* }> EnsureOriginWithArg<O, $t_param:ty> for $name:ty {} ) => {
+		impl_ensure_origin_with_arg_ignoring_arg! {
+			impl <{
+				O: Into<Result<RawOrigin<AccountId, I>, O>> + From<RawOrigin<AccountId, I>>,
+				I: 'static,
+				$( $bound )*
+			}> EnsureOriginWithArg<O, $t_param> for $name {}
+		}
+	};
+	( impl < { O: .. , $( $bound:tt )* }> EnsureOriginWithArg<O, $t_param:ty> for $name:ty {} ) => {
+		impl_ensure_origin_with_arg_ignoring_arg! {
+			impl <{
+				O: Into<Result<RawOrigin<AccountId>, O>> + From<RawOrigin<AccountId>>,
+				$( $bound )*
+			}> EnsureOriginWithArg<O, $t_param> for $name {}
+		}
+	};
+	( impl < { $( $bound:tt )* } > EnsureOriginWithArg<$o_param:ty, $t_param:ty> for $name:ty {} ) => {
+		impl < $( $bound )* > EnsureOriginWithArg<$o_param, $t_param> for $name {
+			type Success = <Self as EnsureOrigin<$o_param>>::Success;
+			fn try_origin(o: $o_param, _: &$t_param) -> Result<Self::Success, $o_param> {
+				<Self as EnsureOrigin<$o_param>>::try_origin(o)
+			}
+			#[cfg(feature = "runtime-benchmarks")]
+			fn try_successful_origin(_: &$t_param) -> Result<$o_param, ()> {
+				<Self as EnsureOrigin<$o_param>>::try_successful_origin()
+			}
+		}
+	}
+}
+
+/// [`EnsureOrigin`] implementation that always fails.
+pub struct NeverEnsureOrigin<Success>(sp_std::marker::PhantomData<Success>);
+impl<OO, Success> EnsureOrigin<OO> for NeverEnsureOrigin<Success> {
+	type Success = Success;
+	fn try_origin(o: OO) -> Result<Success, OO> {
+		Err(o)
+	}
+	#[cfg(feature = "runtime-benchmarks")]
+	fn try_successful_origin() -> Result<OO, ()> {
+		Err(())
+	}
+}
+impl_ensure_origin_with_arg_ignoring_arg! {
+	impl<{ OO, Success, A }>
+		EnsureOriginWithArg<OO, A> for NeverEnsureOrigin<Success>
+	{}
+}
+
 pub struct AsEnsureOriginWithArg<EO>(sp_std::marker::PhantomData<EO>);
 impl<OuterOrigin, Argument, EO: EnsureOrigin<OuterOrigin>>
 	EnsureOriginWithArg<OuterOrigin, Argument> for AsEnsureOriginWithArg<EO>
@@ -207,6 +250,18 @@ impl<O, Original: EnsureOrigin<O>, Mutator: Morph<Original::Success>> EnsureOrig
 		Original::try_successful_origin()
 	}
 }
+impl<O, Original: EnsureOriginWithArg<O, A>, Mutator: Morph<Original::Success>, A>
+	EnsureOriginWithArg<O, A> for MapSuccess<Original, Mutator>
+{
+	type Success = Mutator::Outcome;
+	fn try_origin(o: O, a: &A) -> Result<Mutator::Outcome, O> {
+		Ok(Mutator::morph(Original::try_origin(o, a)?))
+	}
+	#[cfg(feature = "runtime-benchmarks")]
+	fn try_successful_origin(a: &A) -> Result<O, ()> {
+		Original::try_successful_origin(a)
+	}
+}
 
 /// A derivative `EnsureOrigin` implementation. It mutates the `Success` result of an `Original`
 /// implementation with a given `Mutator`, allowing the possibility of an error to be returned
@@ -228,6 +283,43 @@ impl<O: Clone, Original: EnsureOrigin<O>, Mutator: TryMorph<Original::Success>>
 		Original::try_successful_origin()
 	}
 }
+impl<O: Clone, Original: EnsureOriginWithArg<O, A>, Mutator: TryMorph<Original::Success>, A>
+	EnsureOriginWithArg<O, A> for TryMapSuccess<Original, Mutator>
+{
+	type Success = Mutator::Outcome;
+	fn try_origin(o: O, a: &A) -> Result<Mutator::Outcome, O> {
+		let orig = o.clone();
+		Mutator::try_morph(Original::try_origin(o, a)?).map_err(|()| orig)
+	}
+	#[cfg(feature = "runtime-benchmarks")]
+	fn try_successful_origin(a: &A) -> Result<O, ()> {
+		Original::try_successful_origin(a)
+	}
+}
+
+pub struct TryWithMorphedArg<O, A, Morph, Inner, Success>(
+	PhantomData<(O, A, Morph, Inner, Success)>,
+);
+impl<
+		O,
+		A,
+		Morph: for<'a> TryMorph<&'a A>,
+		Inner: for<'a> EnsureOriginWithArg<O, <Morph as TryMorph<&'a A>>::Outcome, Success = Success>,
+		Success,
+	> EnsureOriginWithArg<O, A> for TryWithMorphedArg<O, A, Morph, Inner, Success>
+{
+	type Success = Success;
+	fn try_origin(o: O, a: &A) -> Result<Success, O> {
+		match Morph::try_morph(a) {
+			Ok(x) => Inner::try_origin(o, &x),
+			_ => return Err(o),
+		}
+	}
+	#[cfg(feature = "runtime-benchmarks")]
+	fn try_successful_origin(a: &A) -> Result<O, ()> {
+		Inner::try_successful_origin(&Morph::try_morph(a).map_err(|_| ())?)
+	}
+}
 
 /// "OR gate" implementation of `EnsureOrigin` allowing for different `Success` types for `L`
 /// and `R`, with them combined using an `Either` type.
@@ -250,6 +342,24 @@ impl<OuterOrigin, L: EnsureOrigin<OuterOrigin>, R: EnsureOrigin<OuterOrigin>>
 		L::try_successful_origin().or_else(|()| R::try_successful_origin())
 	}
 }
+impl<
+		OuterOrigin,
+		L: EnsureOriginWithArg<OuterOrigin, Argument>,
+		R: EnsureOriginWithArg<OuterOrigin, Argument>,
+		Argument,
+	> EnsureOriginWithArg<OuterOrigin, Argument> for EitherOfDiverse<L, R>
+{
+	type Success = Either<L::Success, R::Success>;
+	fn try_origin(o: OuterOrigin, a: &Argument) -> Result<Self::Success, OuterOrigin> {
+		L::try_origin(o, a)
+			.map_or_else(|o| R::try_origin(o, a).map(Either::Right), |o| Ok(Either::Left(o)))
+	}
+
+	#[cfg(feature = "runtime-benchmarks")]
+	fn try_successful_origin(a: &Argument) -> Result<OuterOrigin, ()> {
+		L::try_successful_origin(a).or_else(|()| R::try_successful_origin(a))
+	}
+}
 
 /// "OR gate" implementation of `EnsureOrigin` allowing for different `Success` types for `L`
 /// and `R`, with them combined using an `Either` type.
@@ -283,6 +393,23 @@ impl<
 		L::try_successful_origin().or_else(|()| R::try_successful_origin())
 	}
 }
+impl<
+		OuterOrigin,
+		L: EnsureOriginWithArg<OuterOrigin, Argument>,
+		R: EnsureOriginWithArg<OuterOrigin, Argument, Success = L::Success>,
+		Argument,
+	> EnsureOriginWithArg<OuterOrigin, Argument> for EitherOf<L, R>
+{
+	type Success = L::Success;
+	fn try_origin(o: OuterOrigin, a: &Argument) -> Result<Self::Success, OuterOrigin> {
+		L::try_origin(o, a).or_else(|o| R::try_origin(o, a))
+	}
+
+	#[cfg(feature = "runtime-benchmarks")]
+	fn try_successful_origin(a: &Argument) -> Result<OuterOrigin, ()> {
+		L::try_successful_origin(a).or_else(|()| R::try_successful_origin(a))
+	}
+}
 
 /// Type that can be dispatched with an origin but without checking the origin filter.
 ///
@@ -306,6 +433,21 @@ pub trait CallerTrait<AccountId>: Parameter + Member + From<RawOrigin<AccountId>
 
 	/// Extract a reference to the system-level `RawOrigin` if it is that.
 	fn as_system_ref(&self) -> Option<&RawOrigin<AccountId>>;
+
+	/// Extract the signer from it if a system `Signed` origin, `None` otherwise.
+	fn as_signed(&self) -> Option<&AccountId> {
+		self.as_system_ref().and_then(RawOrigin::as_signed)
+	}
+
+	/// Returns `true` if `self` is a system `Root` origin, `None` otherwise.
+	fn is_root(&self) -> bool {
+		self.as_system_ref().map_or(false, RawOrigin::is_root)
+	}
+
+	/// Returns `true` if `self` is a system `None` origin, `None` otherwise.
+	fn is_none(&self) -> bool {
+		self.as_system_ref().map_or(false, RawOrigin::is_none)
+	}
 }
 
 /// Methods available on `frame_system::Config::RuntimeOrigin`.
@@ -356,7 +498,13 @@ pub trait OriginTrait: Sized {
 	fn signed(by: Self::AccountId) -> Self;
 
 	/// Extract the signer from the message if it is a `Signed` origin.
+	#[deprecated = "Use `into_signer` instead"]
 	fn as_signed(self) -> Option<Self::AccountId> {
+		self.into_signer()
+	}
+
+	/// Extract the signer from the message if it is a `Signed` origin.
+	fn into_signer(self) -> Option<Self::AccountId> {
 		self.into_caller().into_system().and_then(|s| {
 			if let RawOrigin::Signed(who) = s {
 				Some(who)
diff --git a/substrate/frame/system/src/lib.rs b/substrate/frame/system/src/lib.rs
index a48a1e459f32ab3caaea755d1d6db586cd8457a7..cbda3d55cc68ccc703fc89314088fc97c7852776 100644
--- a/substrate/frame/system/src/lib.rs
+++ b/substrate/frame/system/src/lib.rs
@@ -89,10 +89,11 @@ use frame_support::{
 		extract_actual_pays_fee, extract_actual_weight, DispatchClass, DispatchInfo,
 		DispatchResult, DispatchResultWithPostInfo, PerDispatchClass,
 	},
+	impl_ensure_origin_with_arg_ignoring_arg,
 	storage::{self, StorageStreamIter},
 	traits::{
-		ConstU32, Contains, EnsureOrigin, Get, HandleLifetime, OnKilledAccount, OnNewAccount,
-		OriginTrait, PalletInfo, SortedMembers, StoredMap, TypedGet,
+		ConstU32, Contains, EnsureOrigin, EnsureOriginWithArg, Get, HandleLifetime,
+		OnKilledAccount, OnNewAccount, OriginTrait, PalletInfo, SortedMembers, StoredMap, TypedGet,
 	},
 	Parameter,
 };
@@ -265,7 +266,7 @@ pub mod pallet {
 		type RuntimeOrigin: Into<Result<RawOrigin<Self::AccountId>, Self::RuntimeOrigin>>
 			+ From<RawOrigin<Self::AccountId>>
 			+ Clone
-			+ OriginTrait<Call = Self::RuntimeCall>;
+			+ OriginTrait<Call = Self::RuntimeCall, AccountId = Self::AccountId>;
 
 		/// The aggregated `RuntimeCall` type.
 		#[pallet::no_default]
@@ -823,6 +824,12 @@ impl<O: Into<Result<RawOrigin<AccountId>, O>> + From<RawOrigin<AccountId>>, Acco
 	}
 }
 
+impl_ensure_origin_with_arg_ignoring_arg! {
+	impl< { O: .., AccountId: Decode, T } >
+		EnsureOriginWithArg<O, T> for EnsureRoot<AccountId>
+	{}
+}
+
 /// Ensure the origin is Root and return the provided `Success` value.
 pub struct EnsureRootWithSuccess<AccountId, Success>(
 	sp_std::marker::PhantomData<(AccountId, Success)>,
@@ -847,6 +854,12 @@ impl<
 	}
 }
 
+impl_ensure_origin_with_arg_ignoring_arg! {
+	impl< { O: .., AccountId: Decode, Success: TypedGet, T } >
+		EnsureOriginWithArg<O, T> for EnsureRootWithSuccess<AccountId, Success>
+	{}
+}
+
 /// Ensure the origin is provided `Ensure` origin and return the provided `Success` value.
 pub struct EnsureWithSuccess<Ensure, AccountId, Success>(
 	sp_std::marker::PhantomData<(Ensure, AccountId, Success)>,
@@ -892,6 +905,12 @@ impl<O: Into<Result<RawOrigin<AccountId>, O>> + From<RawOrigin<AccountId>>, Acco
 	}
 }
 
+impl_ensure_origin_with_arg_ignoring_arg! {
+	impl< { O: .., AccountId: Decode, T } >
+		EnsureOriginWithArg<O, T> for EnsureSigned<AccountId>
+	{}
+}
+
 /// Ensure the origin is `Signed` origin from the given `AccountId`.
 pub struct EnsureSignedBy<Who, AccountId>(sp_std::marker::PhantomData<(Who, AccountId)>);
 impl<
@@ -918,6 +937,12 @@ impl<
 	}
 }
 
+impl_ensure_origin_with_arg_ignoring_arg! {
+	impl< { O: .., Who: SortedMembers<AccountId>, AccountId: PartialEq + Clone + Ord + Decode, T } >
+		EnsureOriginWithArg<O, T> for EnsureSignedBy<Who, AccountId>
+	{}
+}
+
 /// Ensure the origin is `None`. i.e. unsigned transaction.
 pub struct EnsureNone<AccountId>(sp_std::marker::PhantomData<AccountId>);
 impl<O: Into<Result<RawOrigin<AccountId>, O>> + From<RawOrigin<AccountId>>, AccountId>
@@ -937,10 +962,16 @@ impl<O: Into<Result<RawOrigin<AccountId>, O>> + From<RawOrigin<AccountId>>, Acco
 	}
 }
 
+impl_ensure_origin_with_arg_ignoring_arg! {
+	impl< { O: .., AccountId, T } >
+		EnsureOriginWithArg<O, T> for EnsureNone<AccountId>
+	{}
+}
+
 /// Always fail.
-pub struct EnsureNever<T>(sp_std::marker::PhantomData<T>);
-impl<O, T> EnsureOrigin<O> for EnsureNever<T> {
-	type Success = T;
+pub struct EnsureNever<Success>(sp_std::marker::PhantomData<Success>);
+impl<O, Success> EnsureOrigin<O> for EnsureNever<Success> {
+	type Success = Success;
 	fn try_origin(o: O) -> Result<Self::Success, O> {
 		Err(o)
 	}
@@ -951,6 +982,12 @@ impl<O, T> EnsureOrigin<O> for EnsureNever<T> {
 	}
 }
 
+impl_ensure_origin_with_arg_ignoring_arg! {
+	impl< { O, Success, T } >
+		EnsureOriginWithArg<O, T> for EnsureNever<Success>
+	{}
+}
+
 /// Ensure that the origin `o` represents a signed extrinsic (i.e. transaction).
 /// Returns `Ok` with the account that signed the extrinsic or an `Err` otherwise.
 pub fn ensure_signed<OuterOrigin, AccountId>(o: OuterOrigin) -> Result<AccountId, BadOrigin>
diff --git a/substrate/frame/system/src/tests.rs b/substrate/frame/system/src/tests.rs
index 05a7e96fdecb13fa6d9b2c3ac7bdd3ab7814eaa5..165df688b1c2c2915bfdb932a9e1d0448d31b680 100644
--- a/substrate/frame/system/src/tests.rs
+++ b/substrate/frame/system/src/tests.rs
@@ -746,19 +746,20 @@ fn ensure_signed_stuff_works() {
 	}
 
 	let signed_origin = RuntimeOrigin::signed(0u64);
-	assert_ok!(EnsureSigned::try_origin(signed_origin.clone()));
-	assert_ok!(EnsureSignedBy::<Members, _>::try_origin(signed_origin));
+	assert_ok!(<EnsureSigned<_> as EnsureOrigin<_>>::try_origin(signed_origin.clone()));
+	assert_ok!(<EnsureSignedBy<Members, _> as EnsureOrigin<_>>::try_origin(signed_origin));
 
 	#[cfg(feature = "runtime-benchmarks")]
 	{
-		let successful_origin: RuntimeOrigin = EnsureSigned::try_successful_origin()
-			.expect("EnsureSigned has no successful origin required for the test");
-		assert_ok!(EnsureSigned::try_origin(successful_origin));
+		let successful_origin: RuntimeOrigin =
+			<EnsureSigned<_> as EnsureOrigin<_>>::try_successful_origin()
+				.expect("EnsureSigned has no successful origin required for the test");
+		assert_ok!(<EnsureSigned<_> as EnsureOrigin<_>>::try_origin(successful_origin));
 
 		let successful_origin: RuntimeOrigin =
-			EnsureSignedBy::<Members, _>::try_successful_origin()
+			<EnsureSignedBy<Members, _> as EnsureOrigin<_>>::try_successful_origin()
 				.expect("EnsureSignedBy has no successful origin required for the test");
-		assert_ok!(EnsureSignedBy::<Members, _>::try_origin(successful_origin));
+		assert_ok!(<EnsureSignedBy<Members, _> as EnsureOrigin<_>>::try_origin(successful_origin));
 	}
 }
 
diff --git a/substrate/primitives/runtime/src/traits.rs b/substrate/primitives/runtime/src/traits.rs
index a6155e6a4f808f7aaf26884bc5c86c8d5783c22f..9c09bad21d9bc8e3d239b8b1e99b719fc571e261 100644
--- a/substrate/primitives/runtime/src/traits.rs
+++ b/substrate/primitives/runtime/src/traits.rs
@@ -339,6 +339,33 @@ impl<T, A: TryInto<T>> TryMorph<A> for TryMorphInto<T> {
 	}
 }
 
+/// Implementation of `Morph` to retrieve just the first element of a tuple.
+pub struct TakeFirst;
+impl<T1> Morph<(T1,)> for TakeFirst {
+	type Outcome = T1;
+	fn morph(a: (T1,)) -> T1 {
+		a.0
+	}
+}
+impl<T1, T2> Morph<(T1, T2)> for TakeFirst {
+	type Outcome = T1;
+	fn morph(a: (T1, T2)) -> T1 {
+		a.0
+	}
+}
+impl<T1, T2, T3> Morph<(T1, T2, T3)> for TakeFirst {
+	type Outcome = T1;
+	fn morph(a: (T1, T2, T3)) -> T1 {
+		a.0
+	}
+}
+impl<T1, T2, T3, T4> Morph<(T1, T2, T3, T4)> for TakeFirst {
+	type Outcome = T1;
+	fn morph(a: (T1, T2, T3, T4)) -> T1 {
+		a.0
+	}
+}
+
 /// Create a `Morph` and/or `TryMorph` impls with a simple closure-like expression.
 ///
 /// # Examples