diff --git a/substrate/frame/support/procedural/src/construct_runtime/expand/config.rs b/substrate/frame/support/procedural/src/construct_runtime/expand/config.rs
new file mode 100644
index 0000000000000000000000000000000000000000..93d4a868b78478e17bb2a6252cc0373b254da437
--- /dev/null
+++ b/substrate/frame/support/procedural/src/construct_runtime/expand/config.rs
@@ -0,0 +1,123 @@
+// This file is part of Substrate.
+
+// Copyright (C) 2021 Parity Technologies (UK) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// 	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License
+
+use crate::construct_runtime::Pallet;
+use proc_macro2::TokenStream;
+use quote::{format_ident, quote};
+use syn::Ident;
+
+pub fn expand_outer_config(
+	runtime: &Ident,
+	pallet_decls: &[Pallet],
+	scrate: &TokenStream,
+) -> TokenStream {
+	let mut types = TokenStream::new();
+	let mut fields = TokenStream::new();
+	let mut build_storage_calls = TokenStream::new();
+
+	for decl in pallet_decls {
+		if let Some(pallet_entry) = decl.find_part("Config") {
+			let config = format_ident!("{}Config", decl.name);
+			let mod_name = decl.pallet.mod_name();
+			let field_name = if let Some(inst) = decl.instance.as_ref() {
+				format_ident!("{}_{}", mod_name, inst)
+			} else {
+				mod_name
+			};
+			let part_is_generic = !pallet_entry.generics.params.is_empty();
+
+			types.extend(expand_config_types(runtime, decl, &config, part_is_generic));
+			fields.extend(quote!(pub #field_name: #config,));
+			build_storage_calls.extend(expand_config_build_storage_call(scrate, runtime, decl, &field_name));
+		}
+	}
+
+	quote!{
+		#types
+
+		#[cfg(any(feature = "std", test))]
+		use #scrate::serde as __genesis_config_serde_import__;
+		#[cfg(any(feature = "std", test))]
+		#[derive(#scrate::serde::Serialize, #scrate::serde::Deserialize, Default)]
+		#[serde(rename_all = "camelCase")]
+		#[serde(deny_unknown_fields)]
+		#[serde(crate = "__genesis_config_serde_import__")]
+		#[allow(non_snake_case)]
+		pub struct GenesisConfig {
+			#fields
+		}
+
+		#[cfg(any(feature = "std", test))]
+		impl #scrate::sp_runtime::BuildStorage for GenesisConfig {
+			fn assimilate_storage(
+				&self,
+				storage: &mut #scrate::sp_runtime::Storage,
+			) -> std::result::Result<(), String> {
+				#build_storage_calls
+
+				#scrate::BasicExternalities::execute_with_storage(storage, || {
+					<AllPalletsWithSystem as #scrate::traits::OnGenesis>::on_genesis();
+				});
+
+				Ok(())
+			}
+		}
+	}
+}
+
+fn expand_config_types(
+	runtime: &Ident,
+	decl: &Pallet,
+	config: &Ident,
+	part_is_generic: bool,
+) -> TokenStream {
+	let path = &decl.pallet;
+
+	match (decl.instance.as_ref(), part_is_generic) {
+		(Some(inst), true) => quote!{
+			#[cfg(any(feature = "std", test))]
+			pub type #config = #path::GenesisConfig<#runtime, #path::#inst>;
+		},
+		(None, true) => quote!{
+			#[cfg(any(feature = "std", test))]
+			pub type #config = #path::GenesisConfig<#runtime>;
+		},
+		(_, false) => quote!{
+			#[cfg(any(feature = "std", test))]
+			pub type #config = #path::GenesisConfig;
+		},
+	}
+}
+
+fn expand_config_build_storage_call(
+	scrate: &TokenStream,
+	runtime: &Ident,
+	decl: &Pallet,
+	field_name: &Ident,
+) -> TokenStream {
+	let path = &decl.pallet;
+	let instance = if let Some(inst) = decl.instance.as_ref() {
+		quote!(#path::#inst)
+	} else {
+		quote!(#path::__InherentHiddenInstance)
+	};
+
+	quote!{
+		#scrate::sp_runtime::BuildModuleGenesisStorage::
+			<#runtime, #instance>::build_module_genesis_storage(&self.#field_name, storage)?;
+	}
+}
diff --git a/substrate/frame/support/procedural/src/construct_runtime/expand/event.rs b/substrate/frame/support/procedural/src/construct_runtime/expand/event.rs
new file mode 100644
index 0000000000000000000000000000000000000000..c2c905e50ff8de36e764efcc418e1b360c1b5d12
--- /dev/null
+++ b/substrate/frame/support/procedural/src/construct_runtime/expand/event.rs
@@ -0,0 +1,146 @@
+// This file is part of Substrate.
+
+// Copyright (C) 2021 Parity Technologies (UK) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// 	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License
+
+use crate::construct_runtime::{Pallet, parse::PalletPath};
+use proc_macro2::TokenStream;
+use quote::{format_ident, quote};
+use syn::{Generics, Ident};
+
+pub fn expand_outer_event(
+	runtime: &Ident,
+	pallet_decls: &[Pallet],
+	scrate: &TokenStream,
+) -> syn::Result<TokenStream> {
+	let mut event_variants = TokenStream::new();
+	let mut event_conversions = TokenStream::new();
+	let mut events_metadata = TokenStream::new();
+
+	for pallet_decl in pallet_decls {
+		if let Some(pallet_entry) = pallet_decl.find_part("Event") {
+			let path = &pallet_decl.pallet;
+			let index = pallet_decl.index;
+			let instance = pallet_decl.instance.as_ref();
+			let generics = &pallet_entry.generics;
+
+			if instance.is_some() && generics.params.is_empty() {
+				let msg = format!(
+					"Instantiable pallet with no generic `Event` cannot \
+					 be constructed: pallet `{}` must have generic `Event`",
+					pallet_decl.name,
+				);
+				return Err(syn::Error::new(pallet_decl.name.span(), msg));
+			}
+
+			let part_is_generic = !generics.params.is_empty();
+			let pallet_event = match (instance, part_is_generic) {
+				(Some(inst), true) => quote!(#path::Event::<#runtime, #path::#inst>),
+				(Some(inst), false) => quote!(#path::Event::<#path::#inst>),
+				(None, true) => quote!(#path::Event::<#runtime>),
+				(None, false) => quote!(#path::Event),
+			};
+
+			event_variants.extend(expand_event_variant(runtime, path, index, instance, generics));
+			event_conversions.extend(expand_event_conversion(scrate, path, instance, &pallet_event));
+			events_metadata.extend(expand_event_metadata(scrate, path, &pallet_event));
+		}
+	}
+
+	Ok(quote!{
+		#[derive(
+			Clone, PartialEq, Eq,
+			#scrate::codec::Encode,
+			#scrate::codec::Decode,
+			#scrate::RuntimeDebug,
+		)]
+		#[allow(non_camel_case_types)]
+		pub enum Event {
+			#event_variants
+		}
+
+		#event_conversions
+	})
+}
+
+fn expand_event_variant(
+	runtime: &Ident,
+	path: &PalletPath,
+	index: u8,
+	instance: Option<&Ident>,
+	generics: &Generics,
+) -> TokenStream {
+	let part_is_generic = !generics.params.is_empty();
+	let mod_name = &path.mod_name();
+
+	match (instance, part_is_generic) {
+		(Some(inst), true) => {
+			let variant = format_ident!("{}_{}", mod_name, inst);
+			quote!(#[codec(index = #index)] #variant(#path::Event<#runtime, #path::#inst>),)
+		}
+		(Some(inst), false) => {
+			let variant = format_ident!("{}_{}", mod_name, inst);
+			quote!(#[codec(index = #index)] #variant(#path::Event<#path::#inst>),)
+		}
+		(None, true) => {
+			quote!(#[codec(index = #index)] #mod_name(#path::Event<#runtime>),)
+		}
+		(None, false) => {
+			quote!(#[codec(index = #index)] #mod_name(#path::Event),)
+		}
+	}
+}
+
+fn expand_event_conversion(
+	scrate: &TokenStream,
+	path: &PalletPath,
+	instance: Option<&Ident>,
+	pallet_event: &TokenStream,
+) -> TokenStream {
+	let mod_name = path.mod_name();
+	let variant = if let Some(inst) = instance {
+		format_ident!("{}_{}", mod_name, inst)
+	} else {
+		mod_name
+	};
+
+	quote!{
+		impl From<#pallet_event> for Event {
+			fn from(x: #pallet_event) -> Self {
+				Event::#variant(x)
+			}
+		}
+		impl #scrate::sp_std::convert::TryInto<#pallet_event> for Event {
+			type Error = ();
+
+			fn try_into(self) -> #scrate::sp_std::result::Result<#pallet_event, Self::Error> {
+				match self {
+					Self::#variant(evt) => Ok(evt),
+					_ => Err(()),
+				}
+			}
+		}
+	}
+}
+
+fn expand_event_metadata(
+	scrate: &TokenStream,
+	path: &PalletPath,
+	pallet_event: &TokenStream,
+) -> TokenStream {
+	let mod_name = path.mod_name();
+
+	quote!{(stringify!(#mod_name), #scrate::event::FnEncode(#pallet_event::metadata)),}
+}
diff --git a/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs b/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs
new file mode 100644
index 0000000000000000000000000000000000000000..cbabec73d3a6f9c4baccf9a692f54dd8cef61994
--- /dev/null
+++ b/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs
@@ -0,0 +1,190 @@
+// This file is part of Substrate.
+
+// Copyright (C) 2021 Parity Technologies (UK) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// 	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License
+
+use proc_macro2::TokenStream;
+use crate::construct_runtime::Pallet;
+use syn::{Ident, TypePath};
+use quote::quote;
+
+pub fn expand_runtime_metadata(
+	runtime: &Ident,
+	pallet_declarations: &[Pallet],
+	scrate: &TokenStream,
+	extrinsic: &TypePath,
+) -> TokenStream {
+	let modules = pallet_declarations
+		.iter()
+		.filter_map(|pallet_declaration| {
+			pallet_declaration.find_part("Pallet").map(|_| {
+				let filtered_names: Vec<_> = pallet_declaration
+					.pallet_parts()
+					.iter()
+					.filter(|part| part.name() != "Pallet")
+					.map(|part| part.name())
+					.collect();
+				(pallet_declaration, filtered_names)
+			})
+		})
+		.map(|(decl, filtered_names)| {
+			let name = &decl.name;
+			let index = &decl.index;
+			let storage = expand_pallet_metadata_storage(&filtered_names, runtime, scrate, decl);
+			let calls = expand_pallet_metadata_calls(&filtered_names, runtime, scrate, decl);
+			let event = expand_pallet_metadata_events(&filtered_names, runtime, scrate, decl);
+			let constants = expand_pallet_metadata_constants(runtime, scrate, decl);
+			let errors = expand_pallet_metadata_errors(runtime, scrate, decl);
+
+			quote!{
+				#scrate::metadata::ModuleMetadata {
+					name: #scrate::metadata::DecodeDifferent::Encode(stringify!(#name)),
+					index: #index,
+					storage: #storage,
+					calls: #calls,
+					event: #event,
+					constants: #constants,
+					errors: #errors,
+				}
+			}
+		})
+		.collect::<Vec<_>>();
+
+	quote!{
+		impl #runtime {
+			pub fn metadata() -> #scrate::metadata::RuntimeMetadataPrefixed {
+				#scrate::metadata::RuntimeMetadataLastVersion {
+					modules: #scrate::metadata::DecodeDifferent::Encode(&[ #(#modules),* ]),
+					extrinsic: #scrate::metadata::ExtrinsicMetadata {
+						version: <#extrinsic as #scrate::sp_runtime::traits::ExtrinsicMetadata>::VERSION,
+						signed_extensions: <
+								<
+									#extrinsic as #scrate::sp_runtime::traits::ExtrinsicMetadata
+								>::SignedExtensions as #scrate::sp_runtime::traits::SignedExtension
+							>::identifier()
+								.into_iter()
+								.map(#scrate::metadata::DecodeDifferent::Encode)
+								.collect(),
+					},
+				}.into()
+			}
+		}
+	}
+}
+
+fn expand_pallet_metadata_storage(
+	filtered_names: &[&'static str],
+	runtime: &Ident,
+	scrate: &TokenStream,
+	decl: &Pallet,
+) -> TokenStream {
+	if filtered_names.contains(&"Storage") {
+		let instance = decl.instance.as_ref().into_iter();
+		let path = &decl.pallet;
+
+		quote!{
+			Some(#scrate::metadata::DecodeDifferent::Encode(
+				#scrate::metadata::FnEncode(
+					#path::Pallet::<#runtime #(, #path::#instance)*>::storage_metadata
+				)
+			))
+		}
+	} else {
+		quote!(None)
+	}
+}
+
+fn expand_pallet_metadata_calls(
+	filtered_names: &[&'static str],
+	runtime: &Ident,
+	scrate: &TokenStream,
+	decl: &Pallet,
+) -> TokenStream {
+	if filtered_names.contains(&"Call") {
+		let instance = decl.instance.as_ref().into_iter();
+		let path = &decl.pallet;
+
+		quote!{
+			Some(#scrate::metadata::DecodeDifferent::Encode(
+				#scrate::metadata::FnEncode(
+					#path::Pallet::<#runtime #(, #path::#instance)*>::call_functions
+				)
+			))
+		}
+	} else {
+		quote!(None)
+	}
+}
+
+fn expand_pallet_metadata_events(
+	filtered_names: &[&'static str],
+	runtime: &Ident,
+	scrate: &TokenStream,
+	decl: &Pallet,
+) -> TokenStream {
+	if filtered_names.contains(&"Event") {
+		let path = &decl.pallet;
+		let part_is_generic =
+			!decl.find_part("Event").expect("Event part exists; qed").generics.params.is_empty();
+		let pallet_event = match (decl.instance.as_ref(), part_is_generic) {
+			(Some(inst), true) => quote!(#path::Event::<#runtime, #path::#inst>),
+			(Some(inst), false) => quote!(#path::Event::<#path::#inst>),
+			(None, true) => quote!(#path::Event::<#runtime>),
+			(None, false) => quote!(#path::Event),
+		};
+
+		quote!{
+			Some(#scrate::metadata::DecodeDifferent::Encode(
+				#scrate::metadata::FnEncode(#pallet_event::metadata)
+			))
+		}
+	} else {
+		quote!(None)
+	}
+}
+
+fn expand_pallet_metadata_constants(
+	runtime: &Ident,
+	scrate: &TokenStream,
+	decl: &Pallet,
+) -> TokenStream {
+	let path = &decl.pallet;
+	let instance = decl.instance.as_ref().into_iter();
+
+	quote!{
+		#scrate::metadata::DecodeDifferent::Encode(
+			#scrate::metadata::FnEncode(
+				#path::Pallet::<#runtime #(, #path::#instance)*>::module_constants_metadata
+			)
+		)
+	}
+}
+
+fn expand_pallet_metadata_errors(
+	runtime: &Ident,
+	scrate: &TokenStream,
+	decl: &Pallet,
+) -> TokenStream {
+	let path = &decl.pallet;
+	let instance = decl.instance.as_ref().into_iter();
+
+	quote!{
+		#scrate::metadata::DecodeDifferent::Encode(
+			#scrate::metadata::FnEncode(
+				<#path::Pallet::<#runtime #(, #path::#instance)*> as #scrate::metadata::ModuleErrorMetadata>::metadata
+			)
+		)
+	}
+}
diff --git a/substrate/frame/support/procedural/src/construct_runtime/expand/mod.rs b/substrate/frame/support/procedural/src/construct_runtime/expand/mod.rs
new file mode 100644
index 0000000000000000000000000000000000000000..ab2242ba0546ec5bb438e8ea885a7d2be41c82a3
--- /dev/null
+++ b/substrate/frame/support/procedural/src/construct_runtime/expand/mod.rs
@@ -0,0 +1,26 @@
+// This file is part of Substrate.
+
+// Copyright (C) 2021 Parity Technologies (UK) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// 	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License
+
+mod config;
+mod event;
+mod metadata;
+mod origin;
+
+pub use config::expand_outer_config;
+pub use event::expand_outer_event;
+pub use metadata::expand_runtime_metadata;
+pub use origin::expand_outer_origin;
diff --git a/substrate/frame/support/procedural/src/construct_runtime/expand/origin.rs b/substrate/frame/support/procedural/src/construct_runtime/expand/origin.rs
new file mode 100644
index 0000000000000000000000000000000000000000..8ebce237480c856b3e80c1a90fe7f082f65489e0
--- /dev/null
+++ b/substrate/frame/support/procedural/src/construct_runtime/expand/origin.rs
@@ -0,0 +1,341 @@
+// This file is part of Substrate.
+
+// Copyright (C) 2021 Parity Technologies (UK) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// 	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License
+
+use crate::construct_runtime::{parse::PalletPath, Pallet, SYSTEM_PALLET_NAME};
+use proc_macro2::TokenStream;
+use quote::{format_ident, quote};
+use syn::{token, Ident, Generics};
+
+pub fn expand_outer_origin(
+	runtime: &Ident,
+	pallets: &[Pallet],
+	pallets_token: token::Brace,
+	scrate: &TokenStream,
+) -> syn::Result<TokenStream> {
+	let system_pallet = pallets.iter()
+		.find(|decl| decl.name == SYSTEM_PALLET_NAME)
+		.ok_or_else(|| syn::Error::new(
+			pallets_token.span,
+			"`System` pallet declaration is missing. \
+			 Please add this line: `System: frame_system::{Pallet, Call, Storage, Config, Event<T>},`",
+		))?;
+
+	let mut caller_variants = TokenStream::new();
+	let mut pallet_conversions = TokenStream::new();
+
+	for pallet_decl in pallets.iter().filter(|pallet| pallet.name != SYSTEM_PALLET_NAME) {
+		if let Some(pallet_entry) = pallet_decl.find_part("Origin") {
+			let path = &pallet_decl.pallet;
+			let instance = pallet_decl.instance.as_ref();
+			let index = pallet_decl.index;
+			let generics = &pallet_entry.generics;
+
+			if instance.is_some() && generics.params.is_empty() {
+				let msg = format!(
+					"Instantiable pallet with no generic `Origin` cannot \
+					 be constructed: pallet `{}` must have generic `Origin`",
+					pallet_decl.name
+				);
+				return Err(syn::Error::new(pallet_decl.name.span(), msg));
+			}
+
+			caller_variants.extend(
+				expand_origin_caller_variant(runtime, path, index, instance, generics),
+			);
+			pallet_conversions.extend(
+				expand_origin_pallet_conversions(scrate, runtime, path, instance, generics),
+			);
+		}
+	}
+
+	let system_path = &system_pallet.pallet;
+	let system_index = system_pallet.index;
+
+	Ok(quote!{
+		// WARNING: All instance must hold the filter `frame_system::Config::BaseCallFilter`, except
+		// when caller is system Root. One can use `OriginTrait::reset_filter` to do so.
+		#[derive(Clone)]
+		pub struct Origin {
+			caller: OriginCaller,
+			filter: #scrate::sp_std::rc::Rc<Box<dyn Fn(&<#runtime as #system_path::Config>::Call) -> bool>>,
+		}
+
+		#[cfg(not(feature = "std"))]
+		impl #scrate::sp_std::fmt::Debug for Origin {
+			fn fmt(
+				&self,
+				fmt: &mut #scrate::sp_std::fmt::Formatter,
+			) -> #scrate::sp_std::result::Result<(), #scrate::sp_std::fmt::Error> {
+				fmt.write_str("<wasm:stripped>")
+			}
+		}
+
+		#[cfg(feature = "std")]
+		impl #scrate::sp_std::fmt::Debug for Origin {
+			fn fmt(
+				&self,
+				fmt: &mut #scrate::sp_std::fmt::Formatter,
+			) -> #scrate::sp_std::result::Result<(), #scrate::sp_std::fmt::Error> {
+				fmt.debug_struct("Origin")
+					.field("caller", &self.caller)
+					.field("filter", &"[function ptr]")
+					.finish()
+			}
+		}
+
+		impl #scrate::traits::OriginTrait for Origin {
+			type Call = <#runtime as #system_path::Config>::Call;
+			type PalletsOrigin = OriginCaller;
+			type AccountId = <#runtime as #system_path::Config>::AccountId;
+
+			fn add_filter(&mut self, filter: impl Fn(&Self::Call) -> bool + 'static) {
+				let f = self.filter.clone();
+
+				self.filter = #scrate::sp_std::rc::Rc::new(Box::new(move |call| {
+					f(call) && filter(call)
+				}));
+			}
+
+			fn reset_filter(&mut self) {
+				let filter = <
+					<#runtime as #system_path::Config>::BaseCallFilter
+					as #scrate::traits::Filter<<#runtime as #system_path::Config>::Call>
+				>::filter;
+
+				self.filter = #scrate::sp_std::rc::Rc::new(Box::new(filter));
+			}
+
+			fn set_caller_from(&mut self, other: impl Into<Self>) {
+				self.caller = other.into().caller;
+			}
+
+			fn filter_call(&self, call: &Self::Call) -> bool {
+				(self.filter)(call)
+			}
+
+			fn caller(&self) -> &Self::PalletsOrigin {
+				&self.caller
+			}
+
+			fn try_with_caller<R>(
+				mut self,
+				f: impl FnOnce(Self::PalletsOrigin) -> Result<R, Self::PalletsOrigin>,
+			) -> Result<R, Self> {
+				match f(self.caller) {
+					Ok(r) => Ok(r),
+					Err(caller) => { self.caller = caller; Err(self) }
+				}
+			}
+
+			/// Create with system none origin and `frame-system::Config::BaseCallFilter`.
+			fn none() -> Self {
+				#system_path::RawOrigin::None.into()
+			}
+			/// Create with system root origin and no filter.
+			fn root() -> Self {
+				#system_path::RawOrigin::Root.into()
+			}
+			/// Create with system signed origin and `frame-system::Config::BaseCallFilter`.
+			fn signed(by: <#runtime as #system_path::Config>::AccountId) -> Self {
+				#system_path::RawOrigin::Signed(by).into()
+			}
+		}
+
+		#[derive(Clone, PartialEq, Eq, #scrate::RuntimeDebug, #scrate::codec::Encode, #scrate::codec::Decode)]
+		#[allow(non_camel_case_types)]
+		pub enum OriginCaller {
+			#[codec(index = #system_index)]
+			system(#system_path::Origin<#runtime>),
+			#caller_variants
+			#[allow(dead_code)]
+			Void(#scrate::Void)
+		}
+
+		// For backwards compatibility and ease of accessing these functions.
+		#[allow(dead_code)]
+		impl Origin {
+			/// Create with system none origin and `frame-system::Config::BaseCallFilter`.
+			pub fn none() -> Self {
+				<Origin as #scrate::traits::OriginTrait>::none()
+			}
+			/// Create with system root origin and no filter.
+			pub fn root() -> Self {
+				<Origin as #scrate::traits::OriginTrait>::root()
+			}
+			/// Create with system signed origin and `frame-system::Config::BaseCallFilter`.
+			pub fn signed(by: <#runtime as #system_path::Config>::AccountId) -> Self {
+				<Origin as #scrate::traits::OriginTrait>::signed(by)
+			}
+		}
+
+		impl From<#system_path::Origin<#runtime>> for OriginCaller {
+			fn from(x: #system_path::Origin<#runtime>) -> Self {
+				OriginCaller::system(x)
+			}
+		}
+
+		impl #scrate::sp_std::convert::TryFrom<OriginCaller> for #system_path::Origin<#runtime> {
+			type Error = OriginCaller;
+			fn try_from(x: OriginCaller)
+				-> #scrate::sp_std::result::Result<#system_path::Origin<#runtime>, OriginCaller>
+			{
+				if let OriginCaller::system(l) = x {
+					Ok(l)
+				} else {
+					Err(x)
+				}
+			}
+		}
+
+		impl From<#system_path::Origin<#runtime>> for Origin {
+			/// Convert to runtime origin:
+			/// * root origin is built with no filter
+			/// * others use `frame-system::Config::BaseCallFilter`
+			fn from(x: #system_path::Origin<#runtime>) -> Self {
+				let o: OriginCaller = x.into();
+				o.into()
+			}
+		}
+
+		impl From<OriginCaller> for Origin {
+			fn from(x: OriginCaller) -> Self {
+				let mut o = Origin {
+					caller: x,
+					filter: #scrate::sp_std::rc::Rc::new(Box::new(|_| true)),
+				};
+
+				// Root has no filter
+				if !matches!(o.caller, OriginCaller::system(#system_path::Origin::<#runtime>::Root)) {
+					#scrate::traits::OriginTrait::reset_filter(&mut o);
+				}
+
+				o
+			}
+		}
+
+		impl Into<#scrate::sp_std::result::Result<#system_path::Origin<#runtime>, Origin>> for Origin {
+			/// NOTE: converting to pallet origin loses the origin filter information.
+			fn into(self) -> #scrate::sp_std::result::Result<#system_path::Origin<#runtime>, Self> {
+				if let OriginCaller::system(l) = self.caller {
+					Ok(l)
+				} else {
+					Err(self)
+				}
+			}
+		}
+		impl From<Option<<#runtime as #system_path::Config>::AccountId>> for Origin {
+			/// Convert to runtime origin with caller being system signed or none and use filter
+			/// `frame-system::Config::BaseCallFilter`.
+			fn from(x: Option<<#runtime as #system_path::Config>::AccountId>) -> Self {
+				<#system_path::Origin<#runtime>>::from(x).into()
+			}
+		}
+
+		#pallet_conversions
+	})
+}
+
+fn expand_origin_caller_variant(
+	runtime: &Ident,
+	path: &PalletPath,
+	index: u8,
+	instance: Option<&Ident>,
+	generics: &Generics,
+) -> TokenStream {
+	let part_is_generic = !generics.params.is_empty();
+	let mod_name = &path.mod_name();
+
+	match (instance, part_is_generic) {
+		(Some(inst), true) => {
+			let variant = format_ident!("{}_{}", mod_name, inst);
+			quote!(#[codec(index = #index)] #variant(#path::Origin<#runtime, #path::#inst>),)
+		}
+		(Some(inst), false) => {
+			let variant = format_ident!("{}_{}", mod_name, inst);
+			quote!(#[codec(index = #index)] #variant(#path::Origin<#path::#inst>),)
+		}
+		(None, true) => {
+			quote!(#[codec(index = #index)] #mod_name(#path::Origin<#runtime>),)
+		}
+		(None, false) => {
+			quote!(#[codec(index = #index)] #mod_name(#path::Origin),)
+		}
+	}
+}
+
+fn expand_origin_pallet_conversions(
+	scrate: &TokenStream,
+	runtime: &Ident,
+	path: &PalletPath,
+	instance: Option<&Ident>,
+	generics: &Generics,
+) -> TokenStream {
+	let mod_name = path.mod_name();
+	let variant = if let Some(inst) = instance {
+		format_ident!("{}_{}", mod_name, inst)
+	} else {
+		mod_name
+	};
+
+	let part_is_generic = !generics.params.is_empty();
+	let pallet_origin = match (instance, part_is_generic) {
+		(Some(inst), true) => quote!(#path::Origin<#runtime, #path::#inst>),
+		(Some(inst), false) => quote!(#path::Origin<#path::#inst>),
+		(None, true) => quote!(#path::Origin<#runtime>),
+		(None, false) => quote!(#path::Origin),
+	};
+
+	quote!{
+		impl From<#pallet_origin> for OriginCaller {
+			fn from(x: #pallet_origin) -> Self {
+				OriginCaller::#variant(x)
+			}
+		}
+
+		impl From<#pallet_origin> for Origin {
+			/// Convert to runtime origin using `frame-system::Config::BaseCallFilter`.
+			fn from(x: #pallet_origin) -> Self {
+				let x: OriginCaller = x.into();
+				x.into()
+			}
+		}
+
+		impl Into<#scrate::sp_std::result::Result<#pallet_origin, Origin>> for Origin {
+			/// NOTE: converting to pallet origin loses the origin filter information.
+			fn into(self) -> #scrate::sp_std::result::Result<#pallet_origin, Self> {
+				if let OriginCaller::#variant(l) = self.caller {
+					Ok(l)
+				} else {
+					Err(self)
+				}
+			}
+		}
+
+		impl #scrate::sp_std::convert::TryFrom<OriginCaller> for #pallet_origin {
+			type Error = OriginCaller;
+			fn try_from(
+				x: OriginCaller,
+			) -> #scrate::sp_std::result::Result<#pallet_origin, OriginCaller> {
+				if let OriginCaller::#variant(l) = x {
+					Ok(l)
+				} else {
+					Err(x)
+				}
+			}
+		}
+	}
+}
diff --git a/substrate/frame/support/procedural/src/construct_runtime/mod.rs b/substrate/frame/support/procedural/src/construct_runtime/mod.rs
index e14f90197f06026b7a8ac72e802c5bc0f30ee61d..a24168c463aa76a0ada359dfaaa9a27058927d18 100644
--- a/substrate/frame/support/procedural/src/construct_runtime/mod.rs
+++ b/substrate/frame/support/procedural/src/construct_runtime/mod.rs
@@ -15,15 +15,16 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+mod expand;
 mod parse;
 
 use frame_support_procedural_tools::syn_ext as ext;
 use frame_support_procedural_tools::{generate_crate_access, generate_hidden_includes};
-use parse::{PalletDeclaration, RuntimeDefinition, WhereSection, PalletPart};
+use parse::{PalletDeclaration, PalletPart, PalletPath, RuntimeDefinition, WhereSection};
 use proc_macro::TokenStream;
-use proc_macro2::{TokenStream as TokenStream2};
+use proc_macro2::TokenStream as TokenStream2;
 use quote::quote;
-use syn::{Ident, Result, TypePath};
+use syn::{Ident, Result};
 use std::collections::HashMap;
 
 /// The fixed name of the system pallet.
@@ -34,7 +35,7 @@ const SYSTEM_PALLET_NAME: &str = "System";
 pub struct Pallet {
 	pub name: Ident,
 	pub index: u8,
-	pub pallet: Ident,
+	pub pallet: PalletPath,
 	pub instance: Option<Ident>,
 	pub pallet_parts: Vec<PalletPart>,
 }
@@ -134,38 +135,19 @@ fn construct_runtime_parsed(definition: RuntimeDefinition) -> Result<TokenStream
 
 	let pallets = complete_pallets(pallets.into_iter())?;
 
-	let system_pallet = pallets.iter()
-		.find(|decl| decl.name == SYSTEM_PALLET_NAME)
-		.ok_or_else(|| syn::Error::new(
-			pallets_token.span,
-			"`System` pallet declaration is missing. \
-			 Please add this line: `System: frame_system::{Pallet, Call, Storage, Config, Event<T>},`",
-		))?;
-
 	let hidden_crate_name = "construct_runtime";
 	let scrate = generate_crate_access(&hidden_crate_name, "frame-support");
 	let scrate_decl = generate_hidden_includes(&hidden_crate_name, "frame-support");
 
-	let all_but_system_pallets = pallets.iter().filter(|pallet| pallet.name != SYSTEM_PALLET_NAME);
-
-	let outer_event = decl_outer_event(
-		&name,
-		pallets.iter(),
-		&scrate,
-	)?;
+	let outer_event = expand::expand_outer_event(&name, &pallets, &scrate)?;
 
-	let outer_origin = decl_outer_origin(
-		&name,
-		all_but_system_pallets,
-		&system_pallet,
-		&scrate,
-	)?;
+	let outer_origin = expand::expand_outer_origin(&name, &pallets, pallets_token, &scrate)?;
 	let all_pallets = decl_all_pallets(&name, pallets.iter());
 	let pallet_to_index = decl_pallet_runtime_setup(&pallets, &scrate);
 
 	let dispatch = decl_outer_dispatch(&name, pallets.iter(), &scrate);
-	let metadata = decl_runtime_metadata(&name, pallets.iter(), &scrate, &unchecked_extrinsic);
-	let outer_config = decl_outer_config(&name, pallets.iter(), &scrate);
+	let metadata = expand::expand_runtime_metadata(&name, &pallets, &scrate, &unchecked_extrinsic);
+	let outer_config = expand::expand_outer_config(&name, &pallets, &scrate);
 	let inherent = decl_outer_inherent(
 		&name,
 		&block,
@@ -262,85 +244,6 @@ fn decl_outer_inherent<'a>(
 	)
 }
 
-fn decl_outer_config<'a>(
-	runtime: &'a Ident,
-	pallet_declarations: impl Iterator<Item = &'a Pallet>,
-	scrate: &'a TokenStream2,
-) -> TokenStream2 {
-	let pallets_tokens = pallet_declarations
-		.filter_map(|pallet_declaration| {
-			pallet_declaration.find_part("Config").map(|part| {
-				let transformed_generics: Vec<_> = part
-					.generics
-					.params
-					.iter()
-					.map(|param| quote!(<#param>))
-					.collect();
-				(pallet_declaration, transformed_generics)
-			})
-		})
-		.map(|(pallet_declaration, generics)| {
-			let pallet = &pallet_declaration.pallet;
-			let name = Ident::new(
-				&format!("{}Config", pallet_declaration.name),
-				pallet_declaration.name.span(),
-			);
-			let instance = pallet_declaration.instance.as_ref().into_iter();
-			quote!(
-				#name =>
-					#pallet #(#instance)* #(#generics)*,
-			)
-		});
-	quote!(
-		#scrate::impl_outer_config! {
-			pub struct GenesisConfig for #runtime where AllPalletsWithSystem = AllPalletsWithSystem {
-				#(#pallets_tokens)*
-			}
-		}
-	)
-}
-
-fn decl_runtime_metadata<'a>(
-	runtime: &'a Ident,
-	pallet_declarations: impl Iterator<Item = &'a Pallet>,
-	scrate: &'a TokenStream2,
-	extrinsic: &TypePath,
-) -> TokenStream2 {
-	let pallets_tokens = pallet_declarations
-		.filter_map(|pallet_declaration| {
-			pallet_declaration.find_part("Pallet").map(|_| {
-				let filtered_names: Vec<_> = pallet_declaration
-					.pallet_parts()
-					.iter()
-					.filter(|part| part.name() != "Pallet")
-					.map(|part| part.ident())
-					.collect();
-				(pallet_declaration, filtered_names)
-			})
-		})
-		.map(|(pallet_declaration, filtered_names)| {
-			let pallet = &pallet_declaration.pallet;
-			let name = &pallet_declaration.name;
-			let instance = pallet_declaration
-				.instance
-				.as_ref()
-				.map(|name| quote!(<#name>))
-				.into_iter();
-
-			let index = pallet_declaration.index;
-
-			quote!(
-				#pallet::Pallet #(#instance)* as #name { index #index } with #(#filtered_names)*,
-			)
-		});
-	quote!(
-		#scrate::impl_runtime_metadata!{
-			for #runtime with pallets where Extrinsic = #extrinsic
-				#(#pallets_tokens)*
-		}
-	)
-}
-
 fn decl_outer_dispatch<'a>(
 	runtime: &'a Ident,
 	pallet_declarations: impl Iterator<Item = &'a Pallet>,
@@ -349,7 +252,7 @@ fn decl_outer_dispatch<'a>(
 	let pallets_tokens = pallet_declarations
 		.filter(|pallet_declaration| pallet_declaration.exists_part("Call"))
 		.map(|pallet_declaration| {
-			let pallet = &pallet_declaration.pallet;
+			let pallet = &pallet_declaration.pallet.inner.segments.last().unwrap();
 			let name = &pallet_declaration.name;
 			let index = pallet_declaration.index;
 			quote!(#[codec(index = #index)] #pallet::#name)
@@ -364,82 +267,6 @@ fn decl_outer_dispatch<'a>(
 	)
 }
 
-fn decl_outer_origin<'a>(
-	runtime_name: &'a Ident,
-	pallets_except_system: impl Iterator<Item = &'a Pallet>,
-	system_pallet: &'a Pallet,
-	scrate: &'a TokenStream2,
-) -> syn::Result<TokenStream2> {
-	let mut pallets_tokens = TokenStream2::new();
-	for pallet_declaration in pallets_except_system {
-		if let Some(pallet_entry) = pallet_declaration.find_part("Origin") {
-			let pallet = &pallet_declaration.pallet;
-			let instance = pallet_declaration.instance.as_ref();
-			let generics = &pallet_entry.generics;
-			if instance.is_some() && generics.params.is_empty() {
-				let msg = format!(
-					"Instantiable pallet with no generic `Origin` cannot \
-					 be constructed: pallet `{}` must have generic `Origin`",
-					pallet_declaration.name
-				);
-				return Err(syn::Error::new(pallet_declaration.name.span(), msg));
-			}
-			let index = pallet_declaration.index;
-			let tokens = quote!(#[codec(index = #index)] #pallet #instance #generics,);
-			pallets_tokens.extend(tokens);
-		}
-	}
-
-	let system_name = &system_pallet.pallet;
-	let system_index = system_pallet.index;
-
-	Ok(quote!(
-		#scrate::impl_outer_origin! {
-			pub enum Origin for #runtime_name where
-				system = #system_name,
-				system_index = #system_index
-			{
-				#pallets_tokens
-			}
-		}
-	))
-}
-
-fn decl_outer_event<'a>(
-	runtime_name: &'a Ident,
-	pallet_declarations: impl Iterator<Item = &'a Pallet>,
-	scrate: &'a TokenStream2,
-) -> syn::Result<TokenStream2> {
-	let mut pallets_tokens = TokenStream2::new();
-	for pallet_declaration in pallet_declarations {
-		if let Some(pallet_entry) = pallet_declaration.find_part("Event") {
-			let pallet = &pallet_declaration.pallet;
-			let instance = pallet_declaration.instance.as_ref();
-			let generics = &pallet_entry.generics;
-			if instance.is_some() && generics.params.is_empty() {
-				let msg = format!(
-					"Instantiable pallet with no generic `Event` cannot \
-					 be constructed: pallet `{}` must have generic `Event`",
-					pallet_declaration.name,
-				);
-				return Err(syn::Error::new(pallet_declaration.name.span(), msg));
-			}
-
-			let index = pallet_declaration.index;
-			let tokens = quote!(#[codec(index = #index)] #pallet #instance #generics,);
-			pallets_tokens.extend(tokens);
-		}
-	}
-
-	Ok(quote!(
-		#scrate::impl_outer_event! {
-			pub enum Event for #runtime_name {
-				#pallets_tokens
-			}
-		}
-	))
-}
-
 fn decl_all_pallets<'a>(
 	runtime: &'a Ident,
 	pallet_declarations: impl Iterator<Item = &'a Pallet>,
diff --git a/substrate/frame/support/procedural/src/construct_runtime/parse.rs b/substrate/frame/support/procedural/src/construct_runtime/parse.rs
index def207439b5369b9b4b34083fb575c5201289a9f..390729865e98d84deed72e7ca080210ec10e7f0f 100644
--- a/substrate/frame/support/procedural/src/construct_runtime/parse.rs
+++ b/substrate/frame/support/procedural/src/construct_runtime/parse.rs
@@ -16,12 +16,14 @@
 // limitations under the License.
 
 use frame_support_procedural_tools::syn_ext as ext;
-use proc_macro2::Span;
+use proc_macro2::{Span, TokenStream};
 use std::collections::HashSet;
 use syn::{
+	ext::IdentExt,
 	parse::{Parse, ParseStream},
+	punctuated::Punctuated,
 	spanned::Spanned,
-	token, Error, Ident, Result, Token,
+	token, Error, Ident, Path, PathArguments, PathSegment, Result, Token,
 };
 
 mod keyword {
@@ -154,7 +156,7 @@ pub struct PalletDeclaration {
 	pub name: Ident,
 	/// Optional fixed index (e.g. `MyPallet ...  = 3,`)
 	pub index: Option<u8>,
-	pub pallet: Ident,
+	pub pallet: PalletPath,
 	pub instance: Option<Ident>,
 	pub pallet_parts: Vec<PalletPart>,
 }
@@ -164,17 +166,16 @@ impl Parse for PalletDeclaration {
 		let name = input.parse()?;
 		let _: Token![:] = input.parse()?;
 		let pallet = input.parse()?;
-		let instance = if input.peek(Token![::]) && input.peek3(Token![<]) {
-			let _: Token![::] = input.parse()?;
+		let instance = if input.peek(Token![<]) {
 			let _: Token![<] = input.parse()?;
 			let res = Some(input.parse()?);
 			let _: Token![>] = input.parse()?;
+			let _: Token![::] = input.parse()?;
 			res
 		} else {
 			None
 		};
 
-		let _: Token![::] = input.parse()?;
 		let pallet_parts = parse_pallet_parts(input)?;
 
 		let index = if input.peek(Token![=]) {
@@ -198,6 +199,84 @@ impl Parse for PalletDeclaration {
 	}
 }
 
+/// A struct representing a path to a pallet. `PalletPath` is almost identical to the standard
+/// Rust path with a few restrictions:
+/// - No leading colons allowed
+/// - Path segments can only consist of identifers; angle-bracketed or parenthesized segments will
+///   result in a parsing error (except when specifying instances)
+#[derive(Debug, Clone)]
+pub struct PalletPath {
+	pub inner: Path,
+}
+
+impl Parse for PalletPath {
+	fn parse(input: ParseStream) -> Result<Self> {
+		let mut lookahead = input.lookahead1();
+		let mut segments = Punctuated::new();
+
+		if lookahead.peek(Token![crate])
+			|| lookahead.peek(Token![self])
+			|| lookahead.peek(Token![super])
+			|| lookahead.peek(Ident)
+		{
+			let ident = input.call(Ident::parse_any)?;
+			segments.push(PathSegment { ident, arguments: PathArguments::None });
+			let _: Token![::] = input.parse()?;
+			lookahead = input.lookahead1();
+		} else {
+			return Err(lookahead.error());
+		}
+
+		while lookahead.peek(Ident) {
+			let ident = input.parse()?;
+			segments.push(PathSegment { ident, arguments: PathArguments::None });
+			let _: Token![::] = input.parse()?;
+			lookahead = input.lookahead1();
+		}
+
+		if !lookahead.peek(token::Brace) && !lookahead.peek(Token![<]) {
+			return Err(lookahead.error());
+		}
+
+		Ok(Self {
+			inner: Path {
+				leading_colon: None,
+				segments,
+			}
+		})
+	}
+}
+
+impl PalletPath {
+	/// Return the snake-cased module name for this path.
+	pub fn mod_name(&self) -> Ident {
+		let mut iter = self.inner.segments.iter();
+		let mut mod_name = match &iter.next().expect("Path should always have 1 segment; qed").ident {
+			ident if ident == "self" || ident == "super" || ident == "crate" => {
+				// Skip `crate`, `self` and `super` quasi-keywords when creating the module name
+				iter.next()
+					.expect("There must be a path segment pointing to a pallet following \
+						`crate`, `self` or `super`; qed")
+					.ident
+					.clone()
+			}
+			ident => ident.clone(),
+		};
+
+		for segment in iter {
+			mod_name = quote::format_ident!("{}_{}", mod_name, segment.ident);
+		}
+
+		mod_name
+	}
+}
+
+impl quote::ToTokens for PalletPath {
+	fn to_tokens(&self, tokens: &mut TokenStream) {
+		self.inner.to_tokens(tokens);
+	}
+}
+
 /// Parse [`PalletPart`]'s from a braces enclosed list that is split by commas, e.g.
 ///
 /// `{ Call, Event }`
@@ -271,11 +350,6 @@ impl PalletPartKeyword {
 		}
 	}
 
-	/// Returns the name as `Ident`.
-	fn ident(&self) -> Ident {
-		Ident::new(self.name(), self.span())
-	}
-
 	/// Returns `true` if this pallet part is allowed to have generic arguments.
 	fn allows_generic(&self) -> bool {
 		Self::all_generic_arg().iter().any(|n| *n == self.name())
@@ -341,11 +415,6 @@ impl PalletPart {
 	pub fn name(&self) -> &'static str {
 		self.keyword.name()
 	}
-
-	/// The name of this pallet part as `Ident`.
-	pub fn ident(&self) -> Ident {
-		self.keyword.ident()
-	}
 }
 
 fn remove_kind(
diff --git a/substrate/frame/support/test/tests/construct_runtime.rs b/substrate/frame/support/test/tests/construct_runtime.rs
index 76e28a3b152ff6a7802e3c52899caef7d53fe080..6b0a7091edff934c8d12fc5115e6c7c3c2877ca0 100644
--- a/substrate/frame/support/test/tests/construct_runtime.rs
+++ b/substrate/frame/support/test/tests/construct_runtime.rs
@@ -112,8 +112,96 @@ mod module2 {
 	}
 }
 
+mod nested {
+	use super::*;
+
+	pub mod module3 {
+		use super::*;
+
+		pub trait Config: system::Config {}
+
+		frame_support::decl_module! {
+			pub struct Module<T: Config> for enum Call
+				where origin: <T as system::Config>::Origin, system=system
+			{
+				#[weight = 0]
+				pub fn fail(_origin) -> frame_support::dispatch::DispatchResult {
+					Err(Error::<T>::Something.into())
+				}
+
+				fn integrity_test() {
+					INTEGRITY_TEST_EXEC.with(|i| *i.borrow_mut() += 1);
+				}
+			}
+		}
+
+		#[derive(Clone, PartialEq, Eq, Debug, codec::Encode, codec::Decode)]
+		pub struct Origin;
+
+		frame_support::decl_event! {
+			pub enum Event {
+				A,
+			}
+		}
+
+		frame_support::decl_error! {
+			pub enum Error for Module<T: Config> {
+				Something
+			}
+		}
+
+		frame_support::decl_storage! {
+			trait Store for Module<T: Config> as Module {}
+			add_extra_genesis {
+				build(|_config| {})
+			}
+		}
+	}
+}
+
+pub mod module3 {
+	use super::*;
+
+	pub trait Config: system::Config {}
+
+	frame_support::decl_module! {
+		pub struct Module<T: Config> for enum Call
+			where origin: <T as system::Config>::Origin, system=system
+		{
+			#[weight = 0]
+			pub fn fail(_origin) -> frame_support::dispatch::DispatchResult {
+				Err(Error::<T>::Something.into())
+			}
+		}
+	}
+
+	#[derive(Clone, PartialEq, Eq, Debug, codec::Encode, codec::Decode)]
+	pub struct Origin<T>(pub core::marker::PhantomData<T>);
+
+	frame_support::decl_event! {
+		pub enum Event {
+			A,
+		}
+	}
+
+	frame_support::decl_error! {
+		pub enum Error for Module<T: Config> {
+			Something
+		}
+	}
+
+	frame_support::decl_storage! {
+		trait Store for Module<T: Config> as Module {}
+		add_extra_genesis {
+			build(|_config| {})
+		}
+	}
+}
+
 impl<I> module1::Config<I> for Runtime {}
 impl module2::Config for Runtime {}
+impl nested::module3::Config for Runtime {}
+impl module3::Config for Runtime {}
 
 pub type Signature = sr25519::Signature;
 pub type AccountId = <Signature as Verify>::Signer;
@@ -142,6 +230,8 @@ frame_support::construct_runtime!(
 		Module1_1: module1::<Instance1>::{Pallet, Call, Storage, Event<T>, Origin<T>},
 		Module2: module2::{Pallet, Call, Storage, Event, Origin},
 		Module1_2: module1::<Instance2>::{Pallet, Call, Storage, Event<T>, Origin<T>},
+		NestedModule3: nested::module3::{Pallet, Call, Config, Storage, Event, Origin},
+		Module3: self::module3::{Pallet, Call, Config, Storage, Event, Origin<T>},
 		Module1_3: module1::<Instance3>::{Pallet, Storage} = 6,
 		Module1_4: module1::<Instance4>::{Pallet, Call} = 3,
 		Module1_5: module1::<Instance5>::{Pallet, Event<T>},
@@ -156,6 +246,82 @@ pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
 pub type Block = generic::Block<Header, UncheckedExtrinsic>;
 pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<u32, Call, Signature, ()>;
 
+mod origin_test {
+	use frame_support::traits::{Filter, OriginTrait};
+	use super::{module3, nested, system, Block, UncheckedExtrinsic};
+
+	impl nested::module3::Config for RuntimeOriginTest {}
+	impl module3::Config for RuntimeOriginTest {}
+
+	pub struct BaseCallFilter;
+	impl Filter<Call> for BaseCallFilter {
+		fn filter(c: &Call) -> bool {
+			match c {
+				Call::NestedModule3(_) => true,
+				_ => false,
+			}
+		}
+	}
+
+	impl system::Config for RuntimeOriginTest {
+		type BaseCallFilter = BaseCallFilter;
+		type Hash = super::H256;
+		type Origin = Origin;
+		type BlockNumber = super::BlockNumber;
+		type AccountId = u32;
+		type Event = Event;
+		type PalletInfo = PalletInfo;
+		type Call = Call;
+		type DbWeight = ();
+	}
+
+	frame_support::construct_runtime!(
+		pub enum RuntimeOriginTest where
+			Block = Block,
+			NodeBlock = Block,
+			UncheckedExtrinsic = UncheckedExtrinsic
+		{
+			System: system::{Pallet, Event<T>, Origin<T>},
+			NestedModule3: nested::module3::{Pallet, Origin, Call},
+			Module3: module3::{Pallet, Origin<T>, Call},
+		}
+	);
+
+	#[test]
+	fn origin_default_filter() {
+		let accepted_call = nested::module3::Call::fail().into();
+		let rejected_call = module3::Call::fail().into();
+
+		assert_eq!(Origin::root().filter_call(&accepted_call), true);
+		assert_eq!(Origin::root().filter_call(&rejected_call), true);
+		assert_eq!(Origin::none().filter_call(&accepted_call), true);
+		assert_eq!(Origin::none().filter_call(&rejected_call), false);
+		assert_eq!(Origin::signed(0).filter_call(&accepted_call), true);
+		assert_eq!(Origin::signed(0).filter_call(&rejected_call), false);
+		assert_eq!(Origin::from(Some(0)).filter_call(&accepted_call), true);
+		assert_eq!(Origin::from(Some(0)).filter_call(&rejected_call), false);
+		assert_eq!(Origin::from(None).filter_call(&accepted_call), true);
+		assert_eq!(Origin::from(None).filter_call(&rejected_call), false);
+		assert_eq!(Origin::from(super::nested::module3::Origin).filter_call(&accepted_call), true);
+		assert_eq!(Origin::from(super::nested::module3::Origin).filter_call(&rejected_call), false);
+
+		let mut origin = Origin::from(Some(0));
+
+		origin.add_filter(|c| matches!(c, Call::Module3(_)));
+		assert_eq!(origin.filter_call(&accepted_call), false);
+		assert_eq!(origin.filter_call(&rejected_call), false);
+
+		origin.set_caller_from(Origin::root());
+		assert!(matches!(origin.caller, OriginCaller::system(super::system::RawOrigin::Root)));
+		assert_eq!(origin.filter_call(&accepted_call), false);
+		assert_eq!(origin.filter_call(&rejected_call), false);
+
+		origin.reset_filter();
+		assert_eq!(origin.filter_call(&accepted_call), true);
+		assert_eq!(origin.filter_call(&rejected_call), false);
+	}
+}
+
 #[test]
 fn check_modules_error_type() {
 	assert_eq!(
@@ -170,6 +336,10 @@ fn check_modules_error_type() {
 		Module1_2::fail(system::Origin::<Runtime>::Root.into()),
 		Err(DispatchError::Module { index: 33, error: 0, message: Some("Something") }),
 	);
+	assert_eq!(
+		NestedModule3::fail(system::Origin::<Runtime>::Root.into()),
+		Err(DispatchError::Module { index: 34, error: 0, message: Some("Something") }),
+	);
 	assert_eq!(
 		Module1_3::fail(system::Origin::<Runtime>::Root.into()),
 		Err(DispatchError::Module { index: 6, error: 0, message: Some("Something") }),
@@ -203,7 +373,7 @@ fn check_modules_error_type() {
 #[test]
 fn integrity_test_works() {
 	__construct_runtime_integrity_test::runtime_integrity_tests();
-	assert_eq!(INTEGRITY_TEST_EXEC.with(|i| *i.borrow()), 1);
+	assert_eq!(INTEGRITY_TEST_EXEC.with(|i| *i.borrow()), 2);
 }
 
 #[test]
@@ -222,6 +392,12 @@ fn origin_codec() {
 	let origin = OriginCaller::module1_Instance2(module1::Origin(Default::default()));
 	assert_eq!(origin.encode()[0], 33);
 
+	let origin = OriginCaller::nested_module3(nested::module3::Origin);
+	assert_eq!(origin.encode()[0], 34);
+
+	let origin = OriginCaller::module3(module3::Origin(Default::default()));
+	assert_eq!(origin.encode()[0], 35);
+
 	let origin = OriginCaller::module1_Instance6(module1::Origin(Default::default()));
 	assert_eq!(origin.encode()[0], 1);
 
@@ -251,6 +427,12 @@ fn event_codec() {
 	let event = module1::Event::<Runtime, module1::Instance2>::A(Default::default());
 	assert_eq!(Event::from(event).encode()[0], 33);
 
+	let event = nested::module3::Event::A;
+	assert_eq!(Event::from(event).encode()[0], 34);
+
+	let event = module3::Event::A;
+	assert_eq!(Event::from(event).encode()[0], 35);
+
 	let event = module1::Event::<Runtime, module1::Instance5>::A(Default::default());
 	assert_eq!(Event::from(event).encode()[0], 4);
 
@@ -274,6 +456,8 @@ fn call_codec() {
 	assert_eq!(Call::Module1_1(module1::Call::fail()).encode()[0], 31);
 	assert_eq!(Call::Module2(module2::Call::fail()).encode()[0], 32);
 	assert_eq!(Call::Module1_2(module1::Call::fail()).encode()[0], 33);
+	assert_eq!(Call::NestedModule3(nested::module3::Call::fail()).encode()[0], 34);
+	assert_eq!(Call::Module3(module3::Call::fail()).encode()[0], 35);
 	assert_eq!(Call::Module1_4(module1::Call::fail()).encode()[0], 3);
 	assert_eq!(Call::Module1_6(module1::Call::fail()).encode()[0], 1);
 	assert_eq!(Call::Module1_7(module1::Call::fail()).encode()[0], 2);
@@ -381,6 +565,54 @@ fn test_metadata() {
 				errors: DecodeDifferent::Encode(FnEncode(|| &[])),
 				index: 33,
 			},
+			ModuleMetadata {
+				name: DecodeDifferent::Encode("NestedModule3"),
+				storage: Some(DecodeDifferent::Encode(FnEncode(|| StorageMetadata {
+					prefix: DecodeDifferent::Encode("Module"),
+					entries: DecodeDifferent::Encode(&[]),
+				}))),
+				calls: Some(DecodeDifferent::Encode(FnEncode(|| &[
+					FunctionMetadata {
+						name: DecodeDifferent::Encode("fail"),
+						arguments: DecodeDifferent::Encode(&[]),
+						documentation: DecodeDifferent::Encode(&[]),
+					},
+				]))),
+				event: Some(DecodeDifferent::Encode(FnEncode(|| &[
+					EventMetadata {
+						name: DecodeDifferent::Encode("A"),
+						arguments: DecodeDifferent::Encode(&[]),
+						documentation: DecodeDifferent::Encode(&[]),
+					},
+				]))),
+				constants: DecodeDifferent::Encode(FnEncode(|| &[])),
+				errors: DecodeDifferent::Encode(FnEncode(|| &[])),
+				index: 34,
+			},
+			ModuleMetadata {
+				name: DecodeDifferent::Encode("Module3"),
+				storage: Some(DecodeDifferent::Encode(FnEncode(|| StorageMetadata {
+					prefix: DecodeDifferent::Encode("Module"),
+					entries: DecodeDifferent::Encode(&[]),
+				}))),
+				calls: Some(DecodeDifferent::Encode(FnEncode(|| &[
+					FunctionMetadata {
+						name: DecodeDifferent::Encode("fail"),
+						arguments: DecodeDifferent::Encode(&[]),
+						documentation: DecodeDifferent::Encode(&[]),
+					},
+				]))),
+				event: Some(DecodeDifferent::Encode(FnEncode(|| &[
+					EventMetadata {
+						name: DecodeDifferent::Encode("A"),
+						arguments: DecodeDifferent::Encode(&[]),
+						documentation: DecodeDifferent::Encode(&[]),
+					},
+				]))),
+				constants: DecodeDifferent::Encode(FnEncode(|| &[])),
+				errors: DecodeDifferent::Encode(FnEncode(|| &[])),
+				index: 35,
+			},
 			ModuleMetadata {
 				name: DecodeDifferent::Encode("Module1_3"),
 				storage: Some(DecodeDifferent::Encode(FnEncode(|| StorageMetadata {
@@ -522,6 +754,12 @@ fn pallet_in_runtime_is_correct() {
 	assert_eq!(PalletInfo::index::<Module1_2>().unwrap(), 33);
 	assert_eq!(PalletInfo::name::<Module1_2>().unwrap(), "Module1_2");
 
+	assert_eq!(PalletInfo::index::<NestedModule3>().unwrap(), 34);
+	assert_eq!(PalletInfo::name::<NestedModule3>().unwrap(), "NestedModule3");
+
+	assert_eq!(PalletInfo::index::<Module3>().unwrap(), 35);
+	assert_eq!(PalletInfo::name::<Module3>().unwrap(), "Module3");
+
 	assert_eq!(PalletInfo::index::<Module1_3>().unwrap(), 6);
 	assert_eq!(PalletInfo::name::<Module1_3>().unwrap(), "Module1_3");
 
diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/empty_pallet_path.rs b/substrate/frame/support/test/tests/construct_runtime_ui/empty_pallet_path.rs
new file mode 100644
index 0000000000000000000000000000000000000000..bc6abfa82b9cd81af3a56fedc86cac886a36e800
--- /dev/null
+++ b/substrate/frame/support/test/tests/construct_runtime_ui/empty_pallet_path.rs
@@ -0,0 +1,13 @@
+use frame_support::construct_runtime;
+
+construct_runtime! {
+	pub enum Runtime where
+		Block = Block,
+		NodeBlock = Block,
+		UncheckedExtrinsic = UncheckedExtrinsic
+	{
+		system: ,
+	}
+}
+
+fn main() {}
diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/empty_pallet_path.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/empty_pallet_path.stderr
new file mode 100644
index 0000000000000000000000000000000000000000..7102076e5acb05b30d28532db38df72278108b83
--- /dev/null
+++ b/substrate/frame/support/test/tests/construct_runtime_ui/empty_pallet_path.stderr
@@ -0,0 +1,5 @@
+error: expected one of: `crate`, `self`, `super`, identifier
+ --> $DIR/empty_pallet_path.rs:9:11
+  |
+9 |         system: ,
+  |                 ^
diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/invalid_module_details.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/invalid_module_details.stderr
index 559a4637d67ff2cb363c639c7e21765d568ae826..50505b9130cbe5071cb1236276436540ac02ddfa 100644
--- a/substrate/frame/support/test/tests/construct_runtime_ui/invalid_module_details.stderr
+++ b/substrate/frame/support/test/tests/construct_runtime_ui/invalid_module_details.stderr
@@ -1,4 +1,4 @@
-error: expected curly braces
+error: expected one of: identifier, curly braces, `<`
  --> $DIR/invalid_module_details.rs:9:19
   |
 9 |         system: System::(),