diff --git a/Cargo.lock b/Cargo.lock
index 59028fbc61bd679f4827e6132cc068b0e3d1e532..4954c736a6a0d17afee18ec07921ecc19ce9380e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1379,6 +1379,16 @@ dependencies = [
  "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "impl-trait-for-tuples"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "indexmap"
 version = "1.0.2"
@@ -3018,7 +3028,7 @@ dependencies = [
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.2"
+version = "1.0.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -3121,7 +3131,7 @@ name = "quote"
 version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "proc-macro2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -3454,7 +3464,7 @@ name = "rustversion"
 version = "0.1.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "proc-macro2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -3822,6 +3832,7 @@ dependencies = [
 name = "sr-primitives"
 version = "2.0.0"
 dependencies = [
+ "impl-trait-for-tuples 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "integer-sqrt 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -3934,6 +3945,7 @@ dependencies = [
 name = "srml-authorship"
 version = "0.1.0"
 dependencies = [
+ "impl-trait-for-tuples 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "parity-scale-codec 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "sr-io 2.0.0",
  "sr-primitives 2.0.0",
@@ -4092,6 +4104,7 @@ dependencies = [
 name = "srml-finality-tracker"
 version = "2.0.0"
 dependencies = [
+ "impl-trait-for-tuples 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "parity-scale-codec 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)",
  "sr-io 2.0.0",
@@ -4228,6 +4241,7 @@ dependencies = [
 name = "srml-session"
 version = "2.0.0"
 dependencies = [
+ "impl-trait-for-tuples 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "parity-scale-codec 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -4286,6 +4300,7 @@ name = "srml-support"
 version = "2.0.0"
 dependencies = [
  "bitmask 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "impl-trait-for-tuples 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "once_cell 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "parity-scale-codec 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "paste 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -4351,6 +4366,7 @@ name = "srml-system"
 version = "2.0.0"
 dependencies = [
  "criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "impl-trait-for-tuples 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "parity-scale-codec 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -4366,6 +4382,7 @@ dependencies = [
 name = "srml-timestamp"
 version = "2.0.0"
 dependencies = [
+ "impl-trait-for-tuples 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "parity-scale-codec 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)",
  "sr-io 2.0.0",
@@ -5497,7 +5514,7 @@ name = "syn"
 version = "1.0.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "proc-macro2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -6591,6 +6608,7 @@ dependencies = [
 "checksum impl-codec 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "78c441b3d2b5e24b407161e76d482b7bbd29b5da357707839ac40d95152f031f"
 "checksum impl-serde 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5158079de9d4158e0ce1de3ae0bd7be03904efc40b3d7dd8b8c301cbf6b52b56"
 "checksum impl-serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d26be4b97d738552ea423f76c4f681012ff06c3fa36fa968656b3679f60b4a1"
+"checksum impl-trait-for-tuples 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3a9213bd15aa3f974ed007e12e520c435af21e0bb9b016c0874f05eec30034cf"
 "checksum indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7e81a7c05f79578dbc15793d8b619db9ba32b4577003ef3af1a91c416798c58d"
 "checksum integer-sqrt 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ea155abb3ba6f382a75f1418988c05fe82959ed9ce727de427f9cfd425b0c903"
 "checksum interleaved-ordered 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "141340095b15ed7491bd3d4ced9d20cebfb826174b6bb03386381f62b01e3d77"
@@ -6721,7 +6739,7 @@ dependencies = [
 "checksum proc-macro-crate 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e10d4b51f154c8a7fb96fd6dad097cb74b863943ec010ac94b9fd1be8861fe1e"
 "checksum proc-macro-hack 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "982a35d1194084ba319d65c4a68d24ca28f5fdb5b8bc20899e4eef8641ea5178"
 "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
-"checksum proc-macro2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "175a40b9cf564ce9bf050654633dbf339978706b8ead1a907bb970b63185dd95"
+"checksum proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e98a83a9f9b331f54b924e68a66acb1bb35cb01fb0a23645139967abefb697e8"
 "checksum prost 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96d14b1c185652833d24aaad41c5832b0be5616a590227c1fbff57c616754b23"
 "checksum prost-build 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "eb788126ea840817128183f8f603dce02cb7aea25c2a0b764359d8e20010702e"
 "checksum prost-derive 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5e7dc378b94ac374644181a2247cebf59a6ec1c88b49ac77f3a94b86b79d0e11"
diff --git a/core/sr-primitives/Cargo.toml b/core/sr-primitives/Cargo.toml
index d3510e6baa8340a5ed89d09534de7cfa43b61746..19db46e8a2ebbe5a6160aed3efc032cb50de0f73 100644
--- a/core/sr-primitives/Cargo.toml
+++ b/core/sr-primitives/Cargo.toml
@@ -16,6 +16,7 @@ runtime_io = { package = "sr-io", path = "../sr-io", default-features = false }
 log = { version = "0.4", optional = true }
 paste = { version = "0.1"}
 rand = { version = "0.7.0", optional = true }
+impl-trait-for-tuples = "0.1"
 
 [dev-dependencies]
 serde_json = "1.0"
diff --git a/core/sr-primitives/src/traits.rs b/core/sr-primitives/src/traits.rs
index bbcb46be3d52882d0f1176715a7673f0abeb54c8..080b7bc948e0d1f5ba16755223ef8bd7ee44b05b 100644
--- a/core/sr-primitives/src/traits.rs
+++ b/core/sr-primitives/src/traits.rs
@@ -19,8 +19,10 @@
 use rstd::prelude::*;
 use rstd::{self, result, marker::PhantomData, convert::{TryFrom, TryInto}};
 use runtime_io;
-#[cfg(feature = "std")] use std::fmt::{Debug, Display};
-#[cfg(feature = "std")] use serde::{Serialize, Deserialize, de::DeserializeOwned};
+#[cfg(feature = "std")]
+use std::fmt::{Debug, Display};
+#[cfg(feature = "std")]
+use serde::{Serialize, Deserialize, de::DeserializeOwned};
 use primitives::{self, Hasher, Blake2Hasher};
 use crate::codec::{Codec, Encode, Decode, HasCompact};
 use crate::transaction_validity::{
@@ -38,6 +40,7 @@ use rstd::ops::{
 	RemAssign, Shl, Shr
 };
 use crate::AppKey;
+use impl_trait_for_tuples::impl_for_tuples;
 
 /// A lazy value.
 pub trait Lazy<T: ?Sized> {
@@ -404,22 +407,20 @@ impl<T:
 
 /// The block finalization trait. Implementing this lets you express what should happen
 /// for your module when the block is ending.
+#[impl_for_tuples(30)]
 pub trait OnFinalize<BlockNumber> {
 	/// The block is being finalized. Implement to have something happen.
 	fn on_finalize(_n: BlockNumber) {}
 }
 
-impl<N> OnFinalize<N> for () {}
-
 /// The block initialization trait. Implementing this lets you express what should happen
 /// for your module when the block is beginning (right before the first extrinsic is executed).
+#[impl_for_tuples(30)]
 pub trait OnInitialize<BlockNumber> {
 	/// The block is being initialized. Implement to have something happen.
 	fn on_initialize(_n: BlockNumber) {}
 }
 
-impl<N> OnInitialize<N> for () {}
-
 /// Off-chain computation trait.
 ///
 /// Implementing this trait on a module allows you to perform long-running tasks
@@ -428,6 +429,7 @@ impl<N> OnInitialize<N> for () {}
 ///
 /// NOTE: This function runs off-chain, so it can access the block state,
 /// but cannot preform any alterations.
+#[impl_for_tuples(30)]
 pub trait OffchainWorker<BlockNumber> {
 	/// This function is being called on every block.
 	///
@@ -436,47 +438,6 @@ pub trait OffchainWorker<BlockNumber> {
 	fn generate_extrinsics(_n: BlockNumber) {}
 }
 
-impl<N> OffchainWorker<N> for () {}
-
-macro_rules! tuple_impl {
-	($first:ident, $($rest:ident,)+) => {
-		tuple_impl!([$first] [$first] [$($rest)+]);
-	};
-	([$($direct:ident)+] [$($reverse:ident)+] []) => {
-		impl<
-			Number: Copy,
-			$($direct: OnFinalize<Number>),+
-		> OnFinalize<Number> for ($($direct),+,) {
-			fn on_finalize(n: Number) {
-				$($reverse::on_finalize(n);)+
-			}
-		}
-		impl<
-			Number: Copy,
-			$($direct: OnInitialize<Number>),+
-		> OnInitialize<Number> for ($($direct),+,) {
-			fn on_initialize(n: Number) {
-				$($direct::on_initialize(n);)+
-			}
-		}
-		impl<
-			Number: Copy,
-			$($direct: OffchainWorker<Number>),+
-		> OffchainWorker<Number> for ($($direct),+,) {
-			fn generate_extrinsics(n: Number) {
-				$($direct::generate_extrinsics(n);)+
-			}
-		}
-	};
-	([$($direct:ident)+] [$($reverse:ident)+] [$first:ident $($rest:ident)*]) => {
-		tuple_impl!([$($direct)+] [$($reverse)+] []);
-		tuple_impl!([$($direct)+ $first] [$first $($reverse)+] [$($rest)*]);
-	};
-}
-
-#[allow(non_snake_case)]
-tuple_impl!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z,);
-
 /// Abstraction around hashing
 pub trait Hash: 'static + MaybeSerializeDebug + Clone + Eq + PartialEq {	// Stupid bug in the Rust compiler believes derived
 																	// traits must be fulfilled by all type parameters.
@@ -930,96 +891,62 @@ pub trait ModuleDispatchError {
 	fn as_str(&self) -> &'static str;
 }
 
-macro_rules! tuple_impl_indexed {
-	($first:ident, $($rest:ident,)+ ; $first_index:tt, $($rest_index:tt,)+) => {
-		tuple_impl_indexed!([$first] [$($rest)+] ; [$first_index,] [$($rest_index,)+]);
-	};
-	([$($direct:ident)+] ; [$($index:tt,)+]) => {
-		impl<
-			AccountId,
-			Call,
-			$($direct: SignedExtension<AccountId=AccountId, Call=Call>),+
-		> SignedExtension for ($($direct),+,) {
-			type AccountId = AccountId;
-			type Call = Call;
-			type AdditionalSigned = ( $( $direct::AdditionalSigned, )+ );
-			type Pre =  ($($direct::Pre,)+);
-			fn additional_signed(&self) -> Result<Self::AdditionalSigned, TransactionValidityError> {
-				Ok(( $( self.$index.additional_signed()?, )+ ))
-			}
-			fn validate(
-				&self,
-				who: &Self::AccountId,
-				call: &Self::Call,
-				info: DispatchInfo,
-				len: usize,
-			) -> TransactionValidity {
-				let aggregator = vec![
-					$( <$direct as SignedExtension>::validate(&self.$index, who, call, info, len)? ),+
-				];
-				Ok(
-					aggregator.into_iter().fold(
-						ValidTransaction::default(),
-						|acc, a| acc.combine_with(a),
-					)
-				)
-			}
-			fn pre_dispatch(
-				self,
-				who: &Self::AccountId,
-				call: &Self::Call,
-				info: DispatchInfo,
-				len: usize,
-			) -> Result<Self::Pre, $crate::ApplyError> {
-				Ok(($(self.$index.pre_dispatch(who, call, info, len)?,)+))
-			}
-			fn validate_unsigned(
-				call: &Self::Call,
-				info: DispatchInfo,
-				len: usize,
-			) -> TransactionValidity {
-				let aggregator = vec![ $( $direct::validate_unsigned(call, info, len)? ),+ ];
-
-				Ok(
-					aggregator.into_iter().fold(
-						ValidTransaction::default(),
-						|acc, a| acc.combine_with(a),
-					)
-				)
-			}
-			fn pre_dispatch_unsigned(
-				call: &Self::Call,
-				info: DispatchInfo,
-				len: usize,
-			) -> Result<Self::Pre, $crate::ApplyError> {
-				Ok(($($direct::pre_dispatch_unsigned(call, info, len)?,)+))
-			}
-			fn post_dispatch(
-				pre: Self::Pre,
-				info: DispatchInfo,
-				len: usize,
-			) {
-				$($direct::post_dispatch(pre.$index, info, len);)+
-			}
-		}
+#[impl_for_tuples(1, 12)]
+impl<AccountId, Call> SignedExtension for Tuple {
+	for_tuples!( where #( Tuple: SignedExtension<AccountId=AccountId, Call=Call> )* );
+	type AccountId = AccountId;
+	type Call = Call;
+	for_tuples!( type AdditionalSigned = ( #( Tuple::AdditionalSigned ),* ); );
+	for_tuples!( type Pre = ( #( Tuple::Pre ),* ); );
 
-	};
-	([$($direct:ident)+] [] ; [$($index:tt,)+] []) => {
-		tuple_impl_indexed!([$($direct)+] ; [$($index,)+]);
-	};
-	(
-		[$($direct:ident)+] [$first:ident $($rest:ident)*]
-		;
-		[$($index:tt,)+] [$first_index:tt, $($rest_index:tt,)*]
-	) => {
-		tuple_impl_indexed!([$($direct)+] ; [$($index,)+]);
-		tuple_impl_indexed!([$($direct)+ $first] [$($rest)*] ; [$($index,)+ $first_index,] [$($rest_index,)*]);
-	};
-}
+	fn additional_signed(&self) -> Result<Self::AdditionalSigned, TransactionValidityError> {
+		Ok(for_tuples!( ( #( Tuple.additional_signed()? ),* ) ))
+	}
+
+	fn validate(
+		&self,
+		who: &Self::AccountId,
+		call: &Self::Call,
+		info: DispatchInfo,
+		len: usize,
+	) -> TransactionValidity {
+		let valid = ValidTransaction::default();
+		for_tuples!( #( let valid = valid.combine_with(Tuple.validate(who, call, info, len)?); )* );
+		Ok(valid)
+	}
+
+	fn pre_dispatch(self, who: &Self::AccountId, call: &Self::Call, info: DispatchInfo, len: usize)
+		-> Result<Self::Pre, crate::ApplyError>
+	{
+		Ok(for_tuples!( ( #( Tuple.pre_dispatch(who, call, info, len)? ),* ) ))
+	}
+
+	fn validate_unsigned(
+		call: &Self::Call,
+		info: DispatchInfo,
+		len: usize,
+	) -> TransactionValidity {
+		let valid = ValidTransaction::default();
+		for_tuples!( #( let valid = valid.combine_with(Tuple::validate_unsigned(call, info, len)?); )* );
+		Ok(valid)
+	}
 
-// TODO: merge this into `tuple_impl` once codec supports `trait Codec` for longer tuple lengths. #3152
-#[allow(non_snake_case)]
-tuple_impl_indexed!(A, B, C, D, E, F, G, H, I, J, ; 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,);
+	fn pre_dispatch_unsigned(
+		call: &Self::Call,
+		info: DispatchInfo,
+		len: usize,
+	) -> Result<Self::Pre, crate::ApplyError> {
+		Ok(for_tuples!( ( #( Tuple::pre_dispatch_unsigned(call, info, len)? ),* ) ))
+	}
+
+	fn post_dispatch(
+		pre: Self::Pre,
+		info: DispatchInfo,
+		len: usize,
+	) {
+		for_tuples!( #( Tuple::post_dispatch(pre.Tuple, info, len); )* )
+	}
+}
 
 /// Only for bare bone testing when you don't care about signed extensions at all.
 #[cfg(feature = "std")]
diff --git a/srml/authorship/Cargo.toml b/srml/authorship/Cargo.toml
index db3cb133f46842ce003aef2a12d057d4cc9329c3..7bb2af26324dc6ae5ffbc45dfe2497569438a526 100644
--- a/srml/authorship/Cargo.toml
+++ b/srml/authorship/Cargo.toml
@@ -14,6 +14,7 @@ sr-primitives = { path = "../../core/sr-primitives", default-features = false }
 support = { package = "srml-support", path = "../support", default-features = false }
 system = { package = "srml-system", path = "../system", default-features = false }
 runtime-io ={ package = "sr-io", path = "../../core/sr-io", default-features = false }
+impl-trait-for-tuples = "0.1"
 
 [features]
 default = ["std"]
diff --git a/srml/authorship/src/lib.rs b/srml/authorship/src/lib.rs
index e7055dddb87cd4046a311cf5f58d76397168048f..f8a2ad1ed1390bfe7b2211bedef656b7839e2be8 100644
--- a/srml/authorship/src/lib.rs
+++ b/srml/authorship/src/lib.rs
@@ -22,7 +22,7 @@
 
 use rstd::{result, prelude::*};
 use rstd::collections::btree_set::BTreeSet;
-use support::{decl_module, decl_storage, for_each_tuple, StorageValue};
+use support::{decl_module, decl_storage, StorageValue};
 use support::traits::{FindAuthor, VerifySeal, Get};
 use support::dispatch::Result as DispatchResult;
 use codec::{Encode, Decode};
@@ -112,6 +112,7 @@ pub trait Trait: system::Trait {
 
 /// An event handler for the authorship module. There is a dummy implementation
 /// for `()`, which does nothing.
+#[impl_trait_for_tuples::impl_for_tuples(30)]
 pub trait EventHandler<Author, BlockNumber> {
 	/// Note that the given account ID is the author of the current block.
 	fn note_author(author: Author);
@@ -121,30 +122,6 @@ pub trait EventHandler<Author, BlockNumber> {
 	fn note_uncle(author: Author, age: BlockNumber);
 }
 
-macro_rules! impl_event_handler {
-	() => (
-		impl<A, B> EventHandler<A, B> for () {
-			fn note_author(_author: A) { }
-			fn note_uncle(_author: A, _age: B) { }
-		}
-	);
-
-	( $($t:ident)* ) => {
-		impl<Author: Clone, BlockNumber: Clone, $($t: EventHandler<Author, BlockNumber>),*>
-			EventHandler<Author, BlockNumber> for ($($t,)*)
-		{
-			fn note_author(author: Author) {
-				$($t::note_author(author.clone());)*
-			}
-			fn note_uncle(author: Author, age: BlockNumber) {
-				$($t::note_uncle(author.clone(), age.clone());)*
-			}
-		}
-	}
-}
-
-for_each_tuple!(impl_event_handler);
-
 /// Additional filtering on uncles that pass preliminary ancestry checks.
 ///
 /// This should do work such as checking seals
diff --git a/srml/finality-tracker/Cargo.toml b/srml/finality-tracker/Cargo.toml
index 277c4039d22086be7ef1ae32b626af75e9a4f100..ba6c5b7c8fb3e5db732a6cdfe2fabede02407b4f 100644
--- a/srml/finality-tracker/Cargo.toml
+++ b/srml/finality-tracker/Cargo.toml
@@ -12,6 +12,7 @@ rstd = { package = "sr-std", path = "../../core/sr-std", default-features = fals
 sr-primitives = { path = "../../core/sr-primitives", default-features = false }
 support = { package = "srml-support", path = "../support", default-features = false }
 srml-system = { path = "../system", default-features = false }
+impl-trait-for-tuples = "0.1"
 
 [dev-dependencies]
 primitives = { package = "substrate-primitives",  path = "../../core/primitives", default-features = false }
diff --git a/srml/finality-tracker/src/lib.rs b/srml/finality-tracker/src/lib.rs
index 340af3e4d3e4c2fa1e9e9df60eafe6d28cb0cb86..1f90927f7d8e3795fcaf6b77c543e8b5a8c6f85a 100644
--- a/srml/finality-tracker/src/lib.rs
+++ b/srml/finality-tracker/src/lib.rs
@@ -26,7 +26,7 @@ use support::StorageValue;
 use sr_primitives::traits::{One, Zero, SaturatedConversion};
 use rstd::{prelude::*, result, cmp, vec};
 use codec::Decode;
-use support::{decl_module, decl_storage, for_each_tuple};
+use support::{decl_module, decl_storage};
 use support::traits::Get;
 use srml_system::{ensure_none, Trait as SystemTrait};
 
@@ -214,30 +214,13 @@ impl<T: Trait> Module<T> {
 }
 
 /// Called when finalization stalled at a given number.
+#[impl_trait_for_tuples::impl_for_tuples(30)]
 pub trait OnFinalizationStalled<N> {
 	/// The parameter here is how many more blocks to wait before applying
 	/// changes triggered by finality stalling.
 	fn on_stalled(further_wait: N, median: N);
 }
 
-macro_rules! impl_on_stalled {
-	() => (
-		impl<N> OnFinalizationStalled<N> for () {
-			fn on_stalled(_: N, _: N) {}
-		}
-	);
-
-	( $($t:ident)* ) => {
-		impl<NUM: Clone, $($t: OnFinalizationStalled<NUM>),*> OnFinalizationStalled<NUM> for ($($t,)*) {
-			fn on_stalled(further_wait: NUM, median: NUM) {
-				$($t::on_stalled(further_wait.clone(), median.clone());)*
-			}
-		}
-	}
-}
-
-for_each_tuple!(impl_on_stalled);
-
 impl<T: Trait> ProvideInherent for Module<T> {
 	type Call = Call<T>;
 	type Error = MakeFatalError<()>;
diff --git a/srml/session/Cargo.toml b/srml/session/Cargo.toml
index c2e0732ed7058f46e2fba2e46d261220350d1e5a..2e7f5eda805b0ea5c51dee63c5f02cba3604bb93 100644
--- a/srml/session/Cargo.toml
+++ b/srml/session/Cargo.toml
@@ -16,6 +16,7 @@ system = { package = "srml-system", path = "../system", default-features = false
 timestamp = { package = "srml-timestamp", path = "../timestamp", default-features = false }
 substrate-trie = { path = "../../core/trie", default-features = false, optional = true }
 runtime-io ={ package = "sr-io", path = "../../core/sr-io", default-features = false }
+impl-trait-for-tuples = "0.1"
 
 [dev-dependencies]
 primitives = { package = "substrate-primitives",  path = "../../core/primitives" }
diff --git a/srml/session/src/lib.rs b/srml/session/src/lib.rs
index f7c9eee021045bd5ec2f5907ececa69964e238dd..63566fd8810e529824888d7017c7aea38e7d8b64 100644
--- a/srml/session/src/lib.rs
+++ b/srml/session/src/lib.rs
@@ -126,8 +126,8 @@ use sr_primitives::weights::SimpleDispatchInfo;
 use sr_primitives::traits::{Convert, Zero, Member, OpaqueKeys};
 use sr_staking_primitives::SessionIndex;
 use support::{
-	dispatch::Result, ConsensusEngineId, StorageValue, StorageDoubleMap, for_each_tuple,
-	decl_module, decl_event, decl_storage,
+	dispatch::Result, ConsensusEngineId, StorageValue, StorageDoubleMap, decl_module, decl_event,
+	decl_storage,
 };
 use support::{ensure, traits::{OnFreeBalanceZero, Get, FindAuthor}, Parameter};
 use system::{self, ensure_signed};
@@ -251,62 +251,51 @@ pub trait OneSessionHandler<ValidatorId> {
 
 	/// A validator got disabled. Act accordingly until a new session begins.
 	fn on_disabled(_validator_index: usize);
-
 }
 
-macro_rules! impl_session_handlers {
-	() => (
-		impl<AId> SessionHandler<AId> for () {
-			fn on_genesis_session<Ks: OpaqueKeys>(_: &[(AId, Ks)]) {}
-			fn on_new_session<Ks: OpaqueKeys>(_: bool, _: &[(AId, Ks)], _: &[(AId, Ks)]) {}
-			fn on_before_session_ending() {}
-			fn on_disabled(_: usize) {}
-		}
-	);
+#[impl_trait_for_tuples::impl_for_tuples(30)]
+#[tuple_types_no_default_trait_bound]
+impl<AId> SessionHandler<AId> for Tuple {
+	for_tuples!( where #( Tuple: OneSessionHandler<AId> )* );
 
-	( $($t:ident)* ) => {
-		impl<AId, $( $t: OneSessionHandler<AId> ),*> SessionHandler<AId> for ( $( $t , )* ) {
-			fn on_genesis_session<Ks: OpaqueKeys>(validators: &[(AId, Ks)]) {
-				$(
-					let our_keys: Box<dyn Iterator<Item=_>> = Box::new(validators.iter()
-						.map(|k| (&k.0, k.1.get::<$t::Key>(<$t::Key as AppKey>::ID)
-							.unwrap_or_default())));
+	fn on_genesis_session<Ks: OpaqueKeys>(validators: &[(AId, Ks)]) {
+		for_tuples!(
+			#(
+				let our_keys: Box<dyn Iterator<Item=_>> = Box::new(validators.iter()
+					.map(|k| (&k.0, k.1.get::<Tuple::Key>(<Tuple::Key as AppKey>::ID)
+						.unwrap_or_default())));
 
-					$t::on_genesis_session(our_keys);
-				)*
-			}
-			fn on_new_session<Ks: OpaqueKeys>(
-				changed: bool,
-				validators: &[(AId, Ks)],
-				queued_validators: &[(AId, Ks)],
-			) {
-				$(
-					let our_keys: Box<dyn Iterator<Item=_>> = Box::new(validators.iter()
-						.map(|k| (&k.0, k.1.get::<$t::Key>(<$t::Key as AppKey>::ID)
-							.unwrap_or_default())));
-					let queued_keys: Box<dyn Iterator<Item=_>> = Box::new(queued_validators.iter()
-						.map(|k| (&k.0, k.1.get::<$t::Key>(<$t::Key as AppKey>::ID)
-							.unwrap_or_default())));
-					$t::on_new_session(changed, our_keys, queued_keys);
-				)*
-			}
+				Tuple::on_genesis_session(our_keys);
+			)*
+		)
+	}
 
-			fn on_before_session_ending() {
-				$(
-					$t::on_before_session_ending();
-				)*
-			}
+	fn on_new_session<Ks: OpaqueKeys>(
+		changed: bool,
+		validators: &[(AId, Ks)],
+		queued_validators: &[(AId, Ks)],
+	) {
+		for_tuples!(
+			#(
+				let our_keys: Box<dyn Iterator<Item=_>> = Box::new(validators.iter()
+					.map(|k| (&k.0, k.1.get::<Tuple::Key>(<Tuple::Key as AppKey>::ID)
+						.unwrap_or_default())));
+				let queued_keys: Box<dyn Iterator<Item=_>> = Box::new(queued_validators.iter()
+					.map(|k| (&k.0, k.1.get::<Tuple::Key>(<Tuple::Key as AppKey>::ID)
+						.unwrap_or_default())));
+				Tuple::on_new_session(changed, our_keys, queued_keys);
+			)*
+		)
+	}
 
-			fn on_disabled(i: usize) {
-				$(
-					$t::on_disabled(i);
-				)*
-			}
-		}
+	fn on_before_session_ending() {
+		for_tuples!( #( Tuple::on_before_session_ending(); )* )
 	}
-}
 
-for_each_tuple!(impl_session_handlers);
+	fn on_disabled(i: usize) {
+		for_tuples!( #( Tuple::on_disabled(i); )* )
+	}
+}
 
 /// Handler for selecting the genesis validator set.
 pub trait SelectInitialValidators<ValidatorId> {
diff --git a/srml/support/Cargo.toml b/srml/support/Cargo.toml
index f1cdb69a653fd1af36a5de06a0d8af02e89787b8..7a3e0d26e4cdbf0b0d77f358c6465d0cbcbc0c6b 100644
--- a/srml/support/Cargo.toml
+++ b/srml/support/Cargo.toml
@@ -17,6 +17,7 @@ srml-support-procedural = { package = "srml-support-procedural", path = "./proce
 paste = "0.1"
 once_cell = { version = "0.1.6", default-features = false, optional = true }
 bitmask = { version = "0.5", default-features = false }
+impl-trait-for-tuples = "0.1"
 
 [dev-dependencies]
 pretty_assertions = "0.6.1"
diff --git a/srml/support/src/lib.rs b/srml/support/src/lib.rs
index b815e00b9df23b2fdaa60635e6c76ce91e71fd26..13fb69990ef6132a3c56261b075317c6b3688225 100644
--- a/srml/support/src/lib.rs
+++ b/srml/support/src/lib.rs
@@ -266,21 +266,6 @@ pub enum Void {}
 #[doc(hidden)]
 pub use serde::{Serialize, Deserialize};
 
-/// Programatically create derivations for tuples of up to 19 elements. You provide a second macro
-/// which is called once per tuple size, along with a number of identifiers, one for each element
-/// of the tuple.
-#[macro_export]
-macro_rules! for_each_tuple {
-	($m:ident) => {
-		for_each_tuple! { @IMPL $m !! A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, }
-	};
-	(@IMPL $m:ident !!) => { $m! { } };
-	(@IMPL $m:ident !! $h:ident, $($t:ident,)*) => {
-		$m! { $h $($t)* }
-		for_each_tuple! { @IMPL $m !! $($t,)* }
-	}
-}
-
 #[cfg(test)]
 mod tests {
 	use super::*;
diff --git a/srml/support/src/traits.rs b/srml/support/src/traits.rs
index 4ce94bb341ac4f3376d9062b92f2a709b1e16aba..8eeb10c3747469e8e052e6a5f0e681fb6778cf68 100644
--- a/srml/support/src/traits.rs
+++ b/srml/support/src/traits.rs
@@ -24,8 +24,6 @@ use primitives::u32_trait::Value as U32;
 use crate::sr_primitives::traits::{MaybeSerializeDebug, SimpleArithmetic, Saturating};
 use crate::sr_primitives::ConsensusEngineId;
 
-use super::for_each_tuple;
-
 /// Anything that can have a `::len()` method.
 pub trait Len {
 	/// Return the length of data type.
@@ -63,29 +61,12 @@ impl<V: PartialEq, T: Get<V>> Contains<V> for T {
 }
 
 /// The account with the given id was killed.
+#[impl_trait_for_tuples::impl_for_tuples(30)]
 pub trait OnFreeBalanceZero<AccountId> {
 	/// The account was the given id was killed.
 	fn on_free_balance_zero(who: &AccountId);
 }
 
-macro_rules! impl_on_free_balance_zero {
-	() => (
-		impl<AccountId> OnFreeBalanceZero<AccountId> for () {
-			fn on_free_balance_zero(_: &AccountId) {}
-		}
-	);
-
-	( $($t:ident)* ) => {
-		impl<AccountId, $($t: OnFreeBalanceZero<AccountId>),*> OnFreeBalanceZero<AccountId> for ($($t,)*) {
-			fn on_free_balance_zero(who: &AccountId) {
-				$($t::on_free_balance_zero(who);)*
-			}
-		}
-	}
-}
-
-for_each_tuple!(impl_on_free_balance_zero);
-
 /// Trait for a hook to get called when some balance has been minted, causing dilution.
 pub trait OnDilution<Balance> {
 	/// Some `portion` of the total balance just "grew" by `minted`. `portion` is the pre-growth
diff --git a/srml/system/Cargo.toml b/srml/system/Cargo.toml
index f6fd25c29fbcc37640dc92993e2f27d6818ee68d..fd8ae735a9371d958ac0dc5d0148b46084e5f439 100644
--- a/srml/system/Cargo.toml
+++ b/srml/system/Cargo.toml
@@ -14,6 +14,7 @@ runtime-io ={ package = "sr-io", path = "../../core/sr-io", default-features = f
 sr-primitives = { path = "../../core/sr-primitives", default-features = false }
 sr-version = { path = "../../core/sr-version", default-features = false }
 support = { package = "srml-support", path = "../support", default-features = false }
+impl-trait-for-tuples = "0.1"
 
 [dev-dependencies]
 criterion = "0.2"
diff --git a/srml/system/src/lib.rs b/srml/system/src/lib.rs
index 2f1d0ab9e0e202ca1373e72fc810d86612e6f45b..02a70028060f3d5506a22b7ae59c76e51a39f512 100644
--- a/srml/system/src/lib.rs
+++ b/srml/system/src/lib.rs
@@ -112,7 +112,7 @@ use sr_primitives::{
 use primitives::storage::well_known_keys;
 use support::{
 	storage, decl_module, decl_event, decl_storage, StorageDoubleMap, StorageValue, StorageMap,
-	Parameter, for_each_tuple, traits::{Contains, Get}, decl_error,
+	Parameter, traits::{Contains, Get}, decl_error,
 };
 use safe_mix::TripletMix;
 use codec::{Encode, Decode};
@@ -126,29 +126,12 @@ use primitives::ChangesTrieConfiguration;
 pub mod offchain;
 
 /// Handler for when a new account has been created.
+#[impl_trait_for_tuples::impl_for_tuples(30)]
 pub trait OnNewAccount<AccountId> {
 	/// A new account `who` has been registered.
 	fn on_new_account(who: &AccountId);
 }
 
-macro_rules! impl_on_new_account {
-	() => (
-		impl<AccountId> OnNewAccount<AccountId> for () {
-			fn on_new_account(_: &AccountId) {}
-		}
-	);
-
-	( $($t:ident)* ) => {
-		impl<AccountId, $($t: OnNewAccount<AccountId>),*> OnNewAccount<AccountId> for ($($t,)*) {
-			fn on_new_account(who: &AccountId) {
-				$($t::on_new_account(who);)*
-			}
-		}
-	}
-}
-
-for_each_tuple!(impl_on_new_account);
-
 /// Determiner to say whether a given account is unused.
 pub trait IsDeadAccount<AccountId> {
 	/// Is the given account dead?
diff --git a/srml/timestamp/Cargo.toml b/srml/timestamp/Cargo.toml
index 022e478e57ea084397e07e09d1e10d7a01ed8508..00eaf7d7f8376de17a276ca1a443730c957ac678 100644
--- a/srml/timestamp/Cargo.toml
+++ b/srml/timestamp/Cargo.toml
@@ -12,6 +12,7 @@ sr-primitives = { path = "../../core/sr-primitives", default-features = false }
 inherents = { package = "substrate-inherents", path = "../../core/inherents", default-features = false }
 support = { package = "srml-support", path = "../support", default-features = false }
 system = { package = "srml-system", path = "../system", default-features = false }
+impl-trait-for-tuples = "0.1"
 
 [dev-dependencies]
 runtime-io ={ package = "sr-io", path = "../../core/sr-io" }
diff --git a/srml/timestamp/src/lib.rs b/srml/timestamp/src/lib.rs
index cf7792eaa45a31ae775387918b4d9890c071bf79..919e2a75ab7ee6878877a060141263fefd6ffed7 100644
--- a/srml/timestamp/src/lib.rs
+++ b/srml/timestamp/src/lib.rs
@@ -96,7 +96,7 @@ use codec::Encode;
 use codec::Decode;
 #[cfg(feature = "std")]
 use inherents::ProvideInherentData;
-use support::{StorageValue, Parameter, decl_storage, decl_module, for_each_tuple};
+use support::{StorageValue, Parameter, decl_storage, decl_module};
 use support::traits::{Time, Get};
 use sr_primitives::traits::{
 	SimpleArithmetic, Zero, SaturatedConversion, Scale
@@ -183,28 +183,11 @@ impl ProvideInherentData for InherentDataProvider {
 }
 
 /// A trait which is called when the timestamp is set.
+#[impl_trait_for_tuples::impl_for_tuples(30)]
 pub trait OnTimestampSet<Moment> {
 	fn on_timestamp_set(moment: Moment);
 }
 
-macro_rules! impl_timestamp_set {
-	() => (
-		impl<Moment> OnTimestampSet<Moment> for () {
-			fn on_timestamp_set(_: Moment) {}
-		}
-	);
-
-	( $($t:ident)* ) => {
-		impl<Moment: Copy, $($t: OnTimestampSet<Moment>),*> OnTimestampSet<Moment> for ($($t,)*) {
-			fn on_timestamp_set(moment: Moment) {
-				$($t::on_timestamp_set(moment);)*
-			}
-		}
-	}
-}
-
-for_each_tuple!(impl_timestamp_set);
-
 /// The module configuration trait
 pub trait Trait: system::Trait {
 	/// Type used for expressing timestamp.