diff --git a/prdoc/pr_5274.prdoc b/prdoc/pr_5274.prdoc
new file mode 100644
index 0000000000000000000000000000000000000000..fb76ce661b4e2d2d546c557b46c273041b7cff63
--- /dev/null
+++ b/prdoc/pr_5274.prdoc
@@ -0,0 +1,24 @@
+title: Enrich metadata IR with associated types of config traits
+
+doc:
+  - audience: Runtime Dev
+    description: |
+      This feature is part of the upcoming metadata V16. The associated types of the `Config` trait that require the `TypeInfo`
+      or `Parameter` bounds are included in the metadata of the pallet. The metadata is not yet exposed to the end-user, however
+      the metadata intermediate representation (IR) contains these types.
+
+      Developers can opt out of metadata collection of the associated types by specifying `without_metadata` optional attribute
+      to the `#[pallet::config]`.
+
+      Furthermore, the `without_metadata` argument can be used in combination with the newly added `#[pallet::include_metadata]`
+      attribute to selectively include only certain associated types in the metadata collection.
+
+crates:
+  - name: frame-support
+    bump: patch
+  - name: frame-support-procedural
+    bump: patch
+  - name: frame-support-procedural-tools
+    bump: patch
+  - name: sp-metadata-ir
+    bump: major
diff --git a/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs b/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs
index f3724f4ccb69748187b1117977c49a030a55da77..54eb290ca6cf3321729a3f9bba6d10a69e9a547a 100644
--- a/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs
+++ b/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs
@@ -49,6 +49,7 @@ pub fn expand_runtime_metadata(
 			let event = expand_pallet_metadata_events(&filtered_names, runtime, decl);
 			let constants = expand_pallet_metadata_constants(runtime, decl);
 			let errors = expand_pallet_metadata_errors(runtime, decl);
+			let associated_types = expand_pallet_metadata_associated_types(runtime, decl);
 			let docs = expand_pallet_metadata_docs(runtime, decl);
 			let attr = decl.cfg_pattern.iter().fold(TokenStream::new(), |acc, pattern| {
 				let attr = TokenStream::from_str(&format!("#[cfg({})]", pattern.original()))
@@ -70,6 +71,7 @@ pub fn expand_runtime_metadata(
 					constants: #constants,
 					error: #errors,
 					docs: #docs,
+					associated_types: #associated_types,
 					deprecation_info: #deprecation_info,
 				}
 			}
@@ -261,3 +263,12 @@ fn expand_pallet_metadata_docs(runtime: &Ident, decl: &Pallet) -> TokenStream {
 		#path::Pallet::<#runtime #(, #path::#instance)*>::pallet_documentation_metadata()
 	}
 }
+
+fn expand_pallet_metadata_associated_types(runtime: &Ident, decl: &Pallet) -> TokenStream {
+	let path = &decl.path;
+	let instance = decl.instance.as_ref().into_iter();
+
+	quote! {
+		#path::Pallet::<#runtime #(, #path::#instance)*>::pallet_associated_types_metadata()
+	}
+}
diff --git a/substrate/frame/support/procedural/src/lib.rs b/substrate/frame/support/procedural/src/lib.rs
index a2c1e6eec7f78c7074185fe8f1b72f8c70d00b0c..c2f546d92048ac2bc259138b27ac5820227fefd6 100644
--- a/substrate/frame/support/procedural/src/lib.rs
+++ b/substrate/frame/support/procedural/src/lib.rs
@@ -972,6 +972,15 @@ pub fn event(_: TokenStream, _: TokenStream) -> TokenStream {
 	pallet_macro_stub()
 }
 
+///
+/// ---
+///
+/// Documentation for this macro can be found at `frame_support::pallet_macros::include_metadata`.
+#[proc_macro_attribute]
+pub fn include_metadata(_: TokenStream, _: TokenStream) -> TokenStream {
+	pallet_macro_stub()
+}
+
 ///
 /// ---
 ///
diff --git a/substrate/frame/support/procedural/src/pallet/expand/config.rs b/substrate/frame/support/procedural/src/pallet/expand/config.rs
index 5cf4035a8f8b9ddb0f31c3e3b1b8ce36215543ff..0a583f1359bac9dcd7682e3c8c6a4de4eaca9ba9 100644
--- a/substrate/frame/support/procedural/src/pallet/expand/config.rs
+++ b/substrate/frame/support/procedural/src/pallet/expand/config.rs
@@ -95,3 +95,51 @@ Consequently, a runtime that wants to include this pallet must implement this tr
 		_ => Default::default(),
 	}
 }
+
+/// Generate the metadata for the associated types of the config trait.
+///
+/// Implements the `pallet_associated_types_metadata` function for the pallet.
+pub fn expand_config_metadata(def: &Def) -> proc_macro2::TokenStream {
+	let frame_support = &def.frame_support;
+	let type_impl_gen = &def.type_impl_generics(proc_macro2::Span::call_site());
+	let type_use_gen = &def.type_use_generics(proc_macro2::Span::call_site());
+	let pallet_ident = &def.pallet_struct.pallet;
+	let trait_use_gen = &def.trait_use_generics(proc_macro2::Span::call_site());
+
+	let mut where_clauses = vec![&def.config.where_clause];
+	where_clauses.extend(def.extra_constants.iter().map(|d| &d.where_clause));
+	let completed_where_clause = super::merge_where_clauses(&where_clauses);
+
+	let types = def.config.associated_types_metadata.iter().map(|metadata| {
+		let ident = &metadata.ident;
+		let span = ident.span();
+		let ident_str = ident.to_string();
+		let cfgs = &metadata.cfg;
+
+		let no_docs = vec![];
+		let doc = if cfg!(feature = "no-metadata-docs") { &no_docs } else { &metadata.doc };
+
+		quote::quote_spanned!(span => {
+			#( #cfgs ) *
+			#frame_support::__private::metadata_ir::PalletAssociatedTypeMetadataIR {
+				name: #ident_str,
+				ty: #frame_support::__private::scale_info::meta_type::<
+						<T as Config #trait_use_gen>::#ident
+					>(),
+				docs: #frame_support::__private::sp_std::vec![ #( #doc ),* ],
+			}
+		})
+	});
+
+	quote::quote!(
+		impl<#type_impl_gen> #pallet_ident<#type_use_gen> #completed_where_clause {
+
+			#[doc(hidden)]
+			pub fn pallet_associated_types_metadata()
+				-> #frame_support::__private::sp_std::vec::Vec<#frame_support::__private::metadata_ir::PalletAssociatedTypeMetadataIR>
+			{
+				#frame_support::__private::sp_std::vec![ #( #types ),* ]
+			}
+		}
+	)
+}
diff --git a/substrate/frame/support/procedural/src/pallet/expand/mod.rs b/substrate/frame/support/procedural/src/pallet/expand/mod.rs
index 067839c2846353cb995d4c160ac2f38313c19d01..3f9b50f79c0ccf8ea37e23cd79d1bd1aead2064f 100644
--- a/substrate/frame/support/procedural/src/pallet/expand/mod.rs
+++ b/substrate/frame/support/procedural/src/pallet/expand/mod.rs
@@ -60,6 +60,7 @@ pub fn expand(mut def: Def) -> proc_macro2::TokenStream {
 	let constants = constants::expand_constants(&mut def);
 	let pallet_struct = pallet_struct::expand_pallet_struct(&mut def);
 	let config = config::expand_config(&mut def);
+	let associated_types = config::expand_config_metadata(&def);
 	let call = call::expand_call(&mut def);
 	let tasks = tasks::expand_tasks(&mut def);
 	let error = error::expand_error(&mut def);
@@ -101,6 +102,7 @@ storage item. Otherwise, all storage items are listed among [*Type Definitions*]
 		#constants
 		#pallet_struct
 		#config
+		#associated_types
 		#call
 		#tasks
 		#error
diff --git a/substrate/frame/support/procedural/src/pallet/parse/config.rs b/substrate/frame/support/procedural/src/pallet/parse/config.rs
index 9a59d7114202ff4d2b95fe99fdce9d7dbf839bef..6b6dcc802e2e7b39555a831ea2ed8be15190411d 100644
--- a/substrate/frame/support/procedural/src/pallet/parse/config.rs
+++ b/substrate/frame/support/procedural/src/pallet/parse/config.rs
@@ -16,9 +16,9 @@
 // limitations under the License.
 
 use super::helper;
-use frame_support_procedural_tools::{get_doc_literals, is_using_frame_crate};
+use frame_support_procedural_tools::{get_cfg_attributes, get_doc_literals, is_using_frame_crate};
 use quote::ToTokens;
-use syn::{spanned::Spanned, token, Token};
+use syn::{spanned::Spanned, token, Token, TraitItemType};
 
 /// List of additional token to be used for parsing.
 mod keyword {
@@ -36,6 +36,7 @@ mod keyword {
 	syn::custom_keyword!(no_default);
 	syn::custom_keyword!(no_default_bounds);
 	syn::custom_keyword!(constant);
+	syn::custom_keyword!(include_metadata);
 }
 
 #[derive(Default)]
@@ -55,6 +56,8 @@ pub struct ConfigDef {
 	pub has_instance: bool,
 	/// Const associated type.
 	pub consts_metadata: Vec<ConstMetadataDef>,
+	/// Associated types metadata.
+	pub associated_types_metadata: Vec<AssociatedTypeMetadataDef>,
 	/// Whether the trait has the associated type `Event`, note that those bounds are
 	/// checked:
 	/// * `IsType<Self as frame_system::Config>::RuntimeEvent`
@@ -70,6 +73,26 @@ pub struct ConfigDef {
 	pub default_sub_trait: Option<DefaultTrait>,
 }
 
+/// Input definition for an associated type in pallet config.
+pub struct AssociatedTypeMetadataDef {
+	/// Name of the associated type.
+	pub ident: syn::Ident,
+	/// The doc associated.
+	pub doc: Vec<syn::Expr>,
+	/// The cfg associated.
+	pub cfg: Vec<syn::Attribute>,
+}
+
+impl From<&syn::TraitItemType> for AssociatedTypeMetadataDef {
+	fn from(trait_ty: &syn::TraitItemType) -> Self {
+		let ident = trait_ty.ident.clone();
+		let doc = get_doc_literals(&trait_ty.attrs);
+		let cfg = get_cfg_attributes(&trait_ty.attrs);
+
+		Self { ident, doc, cfg }
+	}
+}
+
 /// Input definition for a constant in pallet config.
 pub struct ConstMetadataDef {
 	/// Name of the associated type.
@@ -146,6 +169,8 @@ pub enum PalletAttrType {
 	NoBounds(keyword::no_default_bounds),
 	#[peek(keyword::constant, name = "constant")]
 	Constant(keyword::constant),
+	#[peek(keyword::include_metadata, name = "include_metadata")]
+	IncludeMetadata(keyword::include_metadata),
 }
 
 /// Parsing for `#[pallet::X]`
@@ -322,12 +347,32 @@ pub fn replace_self_by_t(input: proc_macro2::TokenStream) -> proc_macro2::TokenS
 		.collect()
 }
 
+/// Check that the trait item requires the `TypeInfo` bound (or similar).
+fn contains_type_info_bound(ty: &TraitItemType) -> bool {
+	const KNOWN_TYPE_INFO_BOUNDS: &[&str] = &[
+		// Explicit TypeInfo trait.
+		"TypeInfo",
+		// Implicit known substrate traits that implement type info.
+		// Note: Aim to keep this list as small as possible.
+		"Parameter",
+	];
+
+	ty.bounds.iter().any(|bound| {
+		let syn::TypeParamBound::Trait(bound) = bound else { return false };
+
+		KNOWN_TYPE_INFO_BOUNDS
+			.iter()
+			.any(|known| bound.path.segments.last().map_or(false, |last| last.ident == *known))
+	})
+}
+
 impl ConfigDef {
 	pub fn try_from(
 		frame_system: &syn::Path,
 		index: usize,
 		item: &mut syn::Item,
 		enable_default: bool,
+		disable_associated_metadata: bool,
 	) -> syn::Result<Self> {
 		let syn::Item::Trait(item) = item else {
 			let msg = "Invalid pallet::config, expected trait definition";
@@ -368,6 +413,7 @@ impl ConfigDef {
 
 		let mut has_event_type = false;
 		let mut consts_metadata = vec![];
+		let mut associated_types_metadata = vec![];
 		let mut default_sub_trait = if enable_default {
 			Some(DefaultTrait {
 				items: Default::default(),
@@ -383,6 +429,7 @@ impl ConfigDef {
 			let mut already_no_default = false;
 			let mut already_constant = false;
 			let mut already_no_default_bounds = false;
+			let mut already_collected_associated_type = None;
 
 			while let Ok(Some(pallet_attr)) =
 				helper::take_first_item_pallet_attr::<PalletAttr>(trait_item)
@@ -403,11 +450,29 @@ impl ConfigDef {
 							trait_item.span(),
 							"Invalid #[pallet::constant] in #[pallet::config], expected type item",
 						)),
+					// Pallet developer has explicitly requested to include metadata for this associated type.
+					//
+					// They must provide a type item that implements `TypeInfo`.
+					(PalletAttrType::IncludeMetadata(_), syn::TraitItem::Type(ref typ)) => {
+						if already_collected_associated_type.is_some() {
+							return Err(syn::Error::new(
+								pallet_attr._bracket.span.join(),
+								"Duplicate #[pallet::include_metadata] attribute not allowed.",
+							));
+						}
+						already_collected_associated_type = Some(pallet_attr._bracket.span.join());
+						associated_types_metadata.push(AssociatedTypeMetadataDef::from(AssociatedTypeMetadataDef::from(typ)));
+					}
+					(PalletAttrType::IncludeMetadata(_), _) =>
+						return Err(syn::Error::new(
+							pallet_attr._bracket.span.join(),
+							"Invalid #[pallet::include_metadata] in #[pallet::config], expected type item",
+						)),
 					(PalletAttrType::NoDefault(_), _) => {
 						if !enable_default {
 							return Err(syn::Error::new(
 								pallet_attr._bracket.span.join(),
-								"`#[pallet:no_default]` can only be used if `#[pallet::config(with_default)]` \
+								"`#[pallet::no_default]` can only be used if `#[pallet::config(with_default)]` \
 								has been specified"
 							));
 						}
@@ -439,6 +504,47 @@ impl ConfigDef {
 				}
 			}
 
+			if let Some(span) = already_collected_associated_type {
+				// Events and constants are already propagated to the metadata
+				if is_event {
+					return Err(syn::Error::new(
+						span,
+						"Invalid #[pallet::include_metadata] for `type RuntimeEvent`. \
+						The associated type `RuntimeEvent` is already collected in the metadata.",
+					))
+				}
+
+				if already_constant {
+					return Err(syn::Error::new(
+						span,
+						"Invalid #[pallet::include_metadata]: conflict with #[pallet::constant]. \
+						Pallet constant already collect the metadata for the type.",
+					))
+				}
+
+				if let syn::TraitItem::Type(ref ty) = trait_item {
+					if !contains_type_info_bound(ty) {
+						let msg = format!(
+						"Invalid #[pallet::include_metadata] in #[pallet::config], collected type `{}` \
+						does not implement `TypeInfo` or `Parameter`",
+						ty.ident,
+					);
+						return Err(syn::Error::new(span, msg));
+					}
+				}
+			} else {
+				// Metadata of associated types is collected by default, if the associated type
+				// implements `TypeInfo`, or a similar trait that requires the `TypeInfo` bound.
+				if !disable_associated_metadata && !is_event && !already_constant {
+					if let syn::TraitItem::Type(ref ty) = trait_item {
+						// Collect the metadata of the associated type if it implements `TypeInfo`.
+						if contains_type_info_bound(ty) {
+							associated_types_metadata.push(AssociatedTypeMetadataDef::from(ty));
+						}
+					}
+				}
+			}
+
 			if !already_no_default && enable_default {
 				default_sub_trait
 					.as_mut()
@@ -481,6 +587,7 @@ impl ConfigDef {
 			index,
 			has_instance,
 			consts_metadata,
+			associated_types_metadata,
 			has_event_type,
 			where_clause,
 			default_sub_trait,
diff --git a/substrate/frame/support/procedural/src/pallet/parse/mod.rs b/substrate/frame/support/procedural/src/pallet/parse/mod.rs
index b9c7afcab0f917b4242543a2967e3e9a9de999e0..5036f691690f663939359d3596cd2c582571f1b2 100644
--- a/substrate/frame/support/procedural/src/pallet/parse/mod.rs
+++ b/substrate/frame/support/procedural/src/pallet/parse/mod.rs
@@ -108,12 +108,13 @@ impl Def {
 			let pallet_attr: Option<PalletAttr> = helper::take_first_item_pallet_attr(item)?;
 
 			match pallet_attr {
-				Some(PalletAttr::Config(_, with_default)) if config.is_none() =>
+				Some(PalletAttr::Config{ with_default, without_automatic_metadata, ..}) if config.is_none() =>
 					config = Some(config::ConfigDef::try_from(
 						&frame_system,
 						index,
 						item,
 						with_default,
+						without_automatic_metadata,
 					)?),
 				Some(PalletAttr::Pallet(span)) if pallet_struct.is_none() => {
 					let p = pallet_struct::PalletStructDef::try_from(span, index, item)?;
@@ -547,6 +548,7 @@ mod keyword {
 	syn::custom_keyword!(event);
 	syn::custom_keyword!(config);
 	syn::custom_keyword!(with_default);
+	syn::custom_keyword!(without_automatic_metadata);
 	syn::custom_keyword!(hooks);
 	syn::custom_keyword!(inherent);
 	syn::custom_keyword!(error);
@@ -560,10 +562,37 @@ mod keyword {
 	syn::custom_keyword!(composite_enum);
 }
 
+/// The possible values for the `#[pallet::config]` attribute.
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+enum ConfigValue {
+	/// `#[pallet::config(with_default)]`
+	WithDefault(keyword::with_default),
+	/// `#[pallet::config(without_automatic_metadata)]`
+	WithoutAutomaticMetadata(keyword::without_automatic_metadata),
+}
+
+impl syn::parse::Parse for ConfigValue {
+	fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
+		let lookahead = input.lookahead1();
+
+		if lookahead.peek(keyword::with_default) {
+			input.parse().map(ConfigValue::WithDefault)
+		} else if lookahead.peek(keyword::without_automatic_metadata) {
+			input.parse().map(ConfigValue::WithoutAutomaticMetadata)
+		} else {
+			Err(lookahead.error())
+		}
+	}
+}
+
 /// Parse attributes for item in pallet module
 /// syntax must be `pallet::` (e.g. `#[pallet::config]`)
 enum PalletAttr {
-	Config(proc_macro2::Span, bool),
+	Config {
+		span: proc_macro2::Span,
+		with_default: bool,
+		without_automatic_metadata: bool,
+	},
 	Pallet(proc_macro2::Span),
 	Hooks(proc_macro2::Span),
 	/// A `#[pallet::call]` with optional attributes to specialize the behaviour.
@@ -625,7 +654,7 @@ enum PalletAttr {
 impl PalletAttr {
 	fn span(&self) -> proc_macro2::Span {
 		match self {
-			Self::Config(span, _) => *span,
+			Self::Config { span, .. } => *span,
 			Self::Pallet(span) => *span,
 			Self::Hooks(span) => *span,
 			Self::Tasks(span) => *span,
@@ -660,13 +689,49 @@ impl syn::parse::Parse for PalletAttr {
 		let lookahead = content.lookahead1();
 		if lookahead.peek(keyword::config) {
 			let span = content.parse::<keyword::config>()?.span();
-			let with_default = content.peek(syn::token::Paren);
-			if with_default {
+			if content.peek(syn::token::Paren) {
 				let inside_config;
+
+				// Parse (with_default, without_automatic_metadata) attributes.
 				let _paren = syn::parenthesized!(inside_config in content);
-				inside_config.parse::<keyword::with_default>()?;
+
+				let fields: syn::punctuated::Punctuated<ConfigValue, syn::Token![,]> =
+					inside_config.parse_terminated(ConfigValue::parse, syn::Token![,])?;
+				let config_values = fields.iter().collect::<Vec<_>>();
+
+				let mut with_default = false;
+				let mut without_automatic_metadata = false;
+				for config in config_values {
+					match config {
+						ConfigValue::WithDefault(_) => {
+							if with_default {
+								return Err(syn::Error::new(
+									span,
+									"Invalid duplicated attribute for `#[pallet::config]`. Please remove duplicates: with_default.",
+								));
+							}
+							with_default = true;
+						},
+						ConfigValue::WithoutAutomaticMetadata(_) => {
+							if without_automatic_metadata {
+								return Err(syn::Error::new(
+									span,
+									"Invalid duplicated attribute for `#[pallet::config]`. Please remove duplicates: without_automatic_metadata.",
+								));
+							}
+							without_automatic_metadata = true;
+						},
+					}
+				}
+
+				Ok(PalletAttr::Config { span, with_default, without_automatic_metadata })
+			} else {
+				Ok(PalletAttr::Config {
+					span,
+					with_default: false,
+					without_automatic_metadata: false,
+				})
 			}
-			Ok(PalletAttr::Config(span, with_default))
 		} else if lookahead.peek(keyword::pallet) {
 			Ok(PalletAttr::Pallet(content.parse::<keyword::pallet>()?.span()))
 		} else if lookahead.peek(keyword::hooks) {
diff --git a/substrate/frame/support/procedural/tools/src/lib.rs b/substrate/frame/support/procedural/tools/src/lib.rs
index ea53335a88fd4565e41680e2393b9affb248c975..d1d7efaab01d7efcfbd4d16bc501bcbda1c2ef22 100644
--- a/substrate/frame/support/procedural/tools/src/lib.rs
+++ b/substrate/frame/support/procedural/tools/src/lib.rs
@@ -181,3 +181,17 @@ pub fn get_doc_literals(attrs: &[syn::Attribute]) -> Vec<syn::Expr> {
 		})
 		.collect()
 }
+
+/// Return all cfg attributes literals found.
+pub fn get_cfg_attributes(attrs: &[syn::Attribute]) -> Vec<syn::Attribute> {
+	attrs
+		.iter()
+		.filter_map(|attr| {
+			if let syn::Meta::List(meta) = &attr.meta {
+				meta.path.get_ident().filter(|ident| *ident == "cfg").map(|_| attr.clone())
+			} else {
+				None
+			}
+		})
+		.collect()
+}
diff --git a/substrate/frame/support/src/lib.rs b/substrate/frame/support/src/lib.rs
index d76073a97a3517aa3f7d6d72f66e68adc17c714f..1f2ec71b191f7b965f03ddb55af4127cbb010cee 100644
--- a/substrate/frame/support/src/lib.rs
+++ b/substrate/frame/support/src/lib.rs
@@ -1565,6 +1565,53 @@ pub mod pallet_macros {
 	/// * [`frame_support::derive_impl`].
 	/// * [`#[pallet::no_default]`](`no_default`)
 	/// * [`#[pallet::no_default_bounds]`](`no_default_bounds`)
+	///
+	/// ## Optional: `without_automatic_metadata`
+	///
+	/// By default, the associated types of the `Config` trait that require the `TypeInfo` or
+	/// `Parameter` bounds are included in the metadata of the pallet.
+	///
+	/// The optional `without_automatic_metadata` argument can be used to exclude these
+	/// associated types from the metadata collection.
+	///
+	/// Furthermore, the `without_automatic_metadata` argument can be used in combination with
+	/// the [`#[pallet::include_metadata]`](`include_metadata`) attribute to selectively
+	/// include only certain associated types in the metadata collection.
+	///
+	/// ```
+	/// #[frame_support::pallet]
+	/// mod pallet {
+	/// # 	use frame_support::pallet_prelude::*;
+	/// # 	use frame_system::pallet_prelude::*;
+	/// # 	use core::fmt::Debug;
+	/// # 	use frame_support::traits::Contains;
+	/// #
+	/// # 	pub trait SomeMoreComplexBound {}
+	/// #
+	/// 	#[pallet::pallet]
+	/// 	pub struct Pallet<T>(_);
+	///
+	/// 	#[pallet::config(with_default, without_automatic_metadata)] // <- with_default and without_automatic_metadata are optional
+	/// 	pub trait Config: frame_system::Config {
+	/// 		/// The overarching event type.
+	/// 		#[pallet::no_default_bounds] // Default with bounds is not supported for RuntimeEvent
+	/// 		type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
+	///
+	/// 		/// A simple type.
+	/// 		// Type that would have been included in metadata, but is now excluded.
+	/// 		type SimpleType: From<u32> + TypeInfo;
+	///
+	/// 		// The `pallet::include_metadata` is used to selectively include this type in metadata.
+	/// 		#[pallet::include_metadata]
+	/// 		type SelectivelyInclude: From<u32> + TypeInfo;
+	/// 	}
+	///
+	/// 	#[pallet::event]
+	/// 	pub enum Event<T: Config> {
+	/// 		SomeEvent(u16, u32),
+	/// 	}
+	/// }
+	/// ```
 	pub use frame_support_procedural::config;
 
 	/// Allows defining an enum that gets composed as an aggregate enum by `construct_runtime`.
@@ -1962,6 +2009,17 @@ pub mod pallet_macros {
 	///   will be returned.
 	pub use frame_support_procedural::event;
 
+	/// Selectively includes associated types in the metadata.
+	///
+	/// The optional attribute allows you to selectively include associated types in the
+	/// metadata. This can be attached to trait items that implement `TypeInfo`.
+	///
+	/// By default all collectable associated types are included in the metadata.
+	///
+	/// This attribute can be used in combination with the
+	/// [`#[pallet::config(without_automatic_metadata)]`](`config`).
+	pub use frame_support_procedural::include_metadata;
+
 	/// Allows a pallet to declare a set of functions as a *dispatchable extrinsic*.
 	///
 	/// In slightly simplified terms, this macro declares the set of "transactions" of a
diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/deprecated_where_block.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/deprecated_where_block.stderr
index 59e36775d464315b0786a1faa654be7d21419179..55b19ac1a652691ee609aa127a399958b329c0fb 100644
--- a/substrate/frame/support/test/tests/construct_runtime_ui/deprecated_where_block.stderr
+++ b/substrate/frame/support/test/tests/construct_runtime_ui/deprecated_where_block.stderr
@@ -711,6 +711,31 @@ note: the trait `Config` must be implemented
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info)
 
+error[E0599]: the function or associated item `pallet_associated_types_metadata` exists for struct `Pallet<Runtime>`, but its trait bounds were not satisfied
+  --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1
+   |
+20 |    construct_runtime! {
+   |  __^
+   | | _|
+   | ||
+21 | ||     pub struct Runtime where
+   | ||______________________- doesn't satisfy `Runtime: Config`
+22 | |          Block = Block,
+23 | |          NodeBlock = Block,
+...  |
+27 | |      }
+28 | |  }
+   | |__^ function or associated item cannot be called on `Pallet<Runtime>` due to unsatisfied trait bounds
+   |
+   = note: the following trait bounds were not satisfied:
+           `Runtime: Config`
+note: the trait `Config` must be implemented
+  --> $WORKSPACE/substrate/frame/system/src/lib.rs
+   |
+   |     pub trait Config: 'static + Eq + Clone {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info)
+
 error[E0277]: the trait bound `Runtime: Config` is not satisfied
   --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1
    |
diff --git a/substrate/frame/support/test/tests/pallet_associated_types_metadata.rs b/substrate/frame/support/test/tests/pallet_associated_types_metadata.rs
new file mode 100644
index 0000000000000000000000000000000000000000..a2b916f54c5ed82cb53632922f1661050334cef1
--- /dev/null
+++ b/substrate/frame/support/test/tests/pallet_associated_types_metadata.rs
@@ -0,0 +1,269 @@
+// This file is part of Substrate.
+
+// Copyright (C) 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 frame_support::{derive_impl, traits::ConstU32};
+use scale_info::meta_type;
+use sp_metadata_ir::PalletAssociatedTypeMetadataIR;
+
+pub type BlockNumber = u64;
+pub type Header = sp_runtime::generic::Header<u32, sp_runtime::traits::BlakeTwo256>;
+pub type Block = sp_runtime::generic::Block<Header, UncheckedExtrinsic>;
+pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic<u32, RuntimeCall, (), ()>;
+
+/// Pallet without collectable associated types.
+#[frame_support::pallet]
+pub mod pallet {
+	use frame_support::pallet_prelude::*;
+
+	#[pallet::pallet]
+	pub struct Pallet<T>(_);
+
+	#[pallet::config]
+	pub trait Config: frame_system::Config {
+		// Runtime events already propagated to the metadata.
+		type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
+
+		// Constants are already propagated.
+		#[pallet::constant]
+		type MyGetParam2: Get<u32>;
+	}
+
+	#[pallet::event]
+	pub enum Event<T: Config> {
+		TestEvent,
+	}
+}
+
+/// Pallet with default collectable associated types.
+#[frame_support::pallet]
+pub mod pallet2 {
+	use frame_support::pallet_prelude::*;
+
+	#[pallet::pallet]
+	pub struct Pallet<T>(_);
+
+	#[pallet::config]
+	pub trait Config: frame_system::Config {
+		// Runtime events already propagated to the metadata.
+		type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
+
+		// Constants are already propagated.
+		#[pallet::constant]
+		type MyGetParam2: Get<u32>;
+
+		// Associated type included by default, because it requires TypeInfo bound.
+		/// Nonce doc.
+		type Nonce: TypeInfo;
+
+		// Associated type included by default, because it requires
+		// Parameter bound (indirect TypeInfo).
+		type AccountData: Parameter;
+
+		// Associated type without metadata bounds, not included.
+		type NotIncluded: From<u8>;
+	}
+
+	#[pallet::event]
+	pub enum Event<T: Config> {
+		TestEvent,
+	}
+}
+
+/// Pallet with implicit collectable associated types.
+#[frame_support::pallet]
+pub mod pallet3 {
+	use frame_support::pallet_prelude::*;
+
+	#[pallet::pallet]
+	pub struct Pallet<T>(_);
+
+	// Associated types are not collected by default.
+	#[pallet::config(without_automatic_metadata)]
+	pub trait Config: frame_system::Config {
+		// Runtime events already propagated to the metadata.
+		type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
+
+		// Constants are already propagated.
+		#[pallet::constant]
+		type MyGetParam2: Get<u32>;
+
+		// Explicitly include associated types.
+		#[pallet::include_metadata]
+		type Nonce: TypeInfo;
+
+		type AccountData: Parameter;
+
+		type NotIncluded: From<u8>;
+	}
+
+	#[pallet::event]
+	pub enum Event<T: Config> {
+		TestEvent,
+	}
+}
+
+impl pallet::Config for Runtime {
+	type RuntimeEvent = RuntimeEvent;
+	type MyGetParam2 = ConstU32<10>;
+}
+
+impl pallet2::Config for Runtime {
+	type RuntimeEvent = RuntimeEvent;
+	type MyGetParam2 = ConstU32<10>;
+	type Nonce = u64;
+	type AccountData = u16;
+	type NotIncluded = u8;
+}
+
+impl pallet3::Config for Runtime {
+	type RuntimeEvent = RuntimeEvent;
+	type MyGetParam2 = ConstU32<10>;
+	type Nonce = u64;
+	type AccountData = u16;
+	type NotIncluded = u8;
+}
+
+#[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
+impl frame_system::Config for Runtime {
+	type BlockWeights = ();
+	type BlockLength = ();
+	type DbWeight = ();
+	type BaseCallFilter = frame_support::traits::Everything;
+	type RuntimeOrigin = RuntimeOrigin;
+	type Nonce = u64;
+	type RuntimeCall = RuntimeCall;
+	type Hash = sp_runtime::testing::H256;
+	type Hashing = sp_runtime::traits::BlakeTwo256;
+	type AccountId = u64;
+	type Lookup = sp_runtime::traits::IdentityLookup<Self::AccountId>;
+	type Block = Block;
+	type RuntimeEvent = RuntimeEvent;
+	type Version = ();
+	type PalletInfo = PalletInfo;
+	type AccountData = ();
+	type OnNewAccount = ();
+	type OnKilledAccount = ();
+	type SystemWeightInfo = ();
+	type SS58Prefix = ();
+	type OnSetCode = ();
+	type MaxConsumers = ConstU32<16>;
+}
+
+frame_support::construct_runtime!(
+	pub enum Runtime
+	{
+		System: frame_system,
+		Example: pallet,
+		DefaultInclusion: pallet2,
+		ExplicitInclusion: pallet3,
+	}
+);
+
+#[test]
+fn associated_types_metadata() {
+	fn maybe_docs(doc: Vec<&'static str>) -> Vec<&'static str> {
+		if cfg!(feature = "no-metadata-docs") {
+			vec![]
+		} else {
+			doc
+		}
+	}
+
+	let ir = Runtime::metadata_ir();
+
+	// No associated types to collect.
+	let pallet = ir.pallets.iter().find(|pallet| pallet.name == "Example").unwrap();
+	pretty_assertions::assert_eq!(pallet.associated_types, vec![]);
+
+	// Collect by default types that implement TypeInfo or Parameter.
+	let pallet = ir.pallets.iter().find(|pallet| pallet.name == "DefaultInclusion").unwrap();
+	pretty_assertions::assert_eq!(
+		pallet.associated_types,
+		vec![
+			PalletAssociatedTypeMetadataIR {
+				name: "Nonce",
+				ty: meta_type::<u64>(),
+				docs: maybe_docs(vec![" Nonce doc."]),
+			},
+			PalletAssociatedTypeMetadataIR {
+				name: "AccountData",
+				ty: meta_type::<u16>(),
+				docs: vec![],
+			}
+		]
+	);
+
+	// Explicitly include associated types.
+	let pallet = ir.pallets.iter().find(|pallet| pallet.name == "ExplicitInclusion").unwrap();
+	pretty_assertions::assert_eq!(
+		pallet.associated_types,
+		vec![PalletAssociatedTypeMetadataIR {
+			name: "Nonce",
+			ty: meta_type::<u64>(),
+			docs: vec![],
+		}]
+	);
+
+	// Check system pallet.
+	let pallet = ir.pallets.iter().find(|pallet| pallet.name == "System").unwrap();
+	pretty_assertions::assert_eq!(
+		pallet.associated_types,
+		vec![
+			PalletAssociatedTypeMetadataIR {
+				name: "RuntimeCall",
+				ty: meta_type::<RuntimeCall>(),
+				docs: maybe_docs(vec![" The aggregated `RuntimeCall` type."]),
+			},
+			PalletAssociatedTypeMetadataIR {
+				name: "Nonce",
+				ty: meta_type::<u64>(),
+				docs: maybe_docs(vec![" This stores the number of previous transactions associated with a sender account."]),
+			},
+			PalletAssociatedTypeMetadataIR {
+				name: "Hash",
+				ty: meta_type::<sp_runtime::testing::H256>(),
+				docs: maybe_docs(vec![" The output of the `Hashing` function."]),
+			},
+            PalletAssociatedTypeMetadataIR {
+				name: "Hashing",
+				ty: meta_type::<sp_runtime::traits::BlakeTwo256>(),
+				docs: maybe_docs(vec![" The hashing system (algorithm) being used in the runtime (e.g. Blake2)."]),
+			},
+            PalletAssociatedTypeMetadataIR {
+                name: "AccountId",
+                ty: meta_type::<u64>(),
+                docs: maybe_docs(vec![" The user account identifier type for the runtime."]),
+            },
+            PalletAssociatedTypeMetadataIR {
+                name: "Block",
+                ty: meta_type::<Block>(),
+                docs: maybe_docs(vec![
+                    " The Block type used by the runtime. This is used by `construct_runtime` to retrieve the",
+                    " extrinsics or other block specific data as needed.",
+                ]),
+            },
+            PalletAssociatedTypeMetadataIR {
+                name: "AccountData",
+                ty: meta_type::<()>(),
+                docs: maybe_docs(vec![
+                    " Data to be associated with an account (other than nonce/transaction counter, which this",
+                    " pallet does regardless).",
+                ]),
+            },
+		]
+	);
+}
diff --git a/substrate/frame/support/test/tests/pallet_ui/config_duplicate_attr.rs b/substrate/frame/support/test/tests/pallet_ui/config_duplicate_attr.rs
new file mode 100644
index 0000000000000000000000000000000000000000..f58e11b0226175107846bf0e3e169d2803dcaaf1
--- /dev/null
+++ b/substrate/frame/support/test/tests/pallet_ui/config_duplicate_attr.rs
@@ -0,0 +1,39 @@
+// This file is part of Substrate.
+
+// Copyright (C) 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.
+
+#[frame_support::pallet]
+mod pallet {
+	use frame_support::pallet_prelude::*;
+	use frame_system::pallet_prelude::*;
+
+	#[pallet::config(with_default, without_automatic_metadata, without_automatic_metadata)]
+	pub trait Config: frame_system::Config {
+		#[pallet::constant]
+		type MyGetParam2: Get<u32>;
+	}
+
+	#[pallet::pallet]
+	pub struct Pallet<T>(core::marker::PhantomData<T>);
+
+	#[pallet::hooks]
+	impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {}
+
+	#[pallet::call]
+	impl<T: Config> Pallet<T> {}
+}
+
+fn main() {}
diff --git a/substrate/frame/support/test/tests/pallet_ui/config_duplicate_attr.stderr b/substrate/frame/support/test/tests/pallet_ui/config_duplicate_attr.stderr
new file mode 100644
index 0000000000000000000000000000000000000000..46326bde0559fad89fe22ce70aca77b4fa4b185e
--- /dev/null
+++ b/substrate/frame/support/test/tests/pallet_ui/config_duplicate_attr.stderr
@@ -0,0 +1,5 @@
+error: Invalid duplicated attribute for `#[pallet::config]`. Please remove duplicates: without_automatic_metadata.
+  --> tests/pallet_ui/config_duplicate_attr.rs:23:12
+   |
+23 |     #[pallet::config(with_default, without_automatic_metadata, without_automatic_metadata)]
+   |               ^^^^^^
diff --git a/substrate/frame/support/test/tests/pallet_ui/config_metadata_non_type_info.rs b/substrate/frame/support/test/tests/pallet_ui/config_metadata_non_type_info.rs
new file mode 100644
index 0000000000000000000000000000000000000000..38c3870ba735b6cd34550a8d2e6142cdb62aa372
--- /dev/null
+++ b/substrate/frame/support/test/tests/pallet_ui/config_metadata_non_type_info.rs
@@ -0,0 +1,42 @@
+// This file is part of Substrate.
+
+// Copyright (C) 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.
+
+#[frame_support::pallet]
+mod pallet {
+	use frame_support::pallet_prelude::*;
+	use frame_system::pallet_prelude::*;
+
+	#[pallet::config(with_default)]
+	pub trait Config: frame_system::Config {
+		#[pallet::constant]
+		type MyGetParam2: Get<u32>;
+
+		#[pallet::include_metadata]
+		type MyNonScaleTypeInfo;
+	}
+
+	#[pallet::pallet]
+	pub struct Pallet<T>(core::marker::PhantomData<T>);
+
+	#[pallet::hooks]
+	impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {}
+
+	#[pallet::call]
+	impl<T: Config> Pallet<T> {}
+}
+
+fn main() {}
diff --git a/substrate/frame/support/test/tests/pallet_ui/config_metadata_non_type_info.stderr b/substrate/frame/support/test/tests/pallet_ui/config_metadata_non_type_info.stderr
new file mode 100644
index 0000000000000000000000000000000000000000..362e97e8bb92c24531f23db4820fcff7210e1a53
--- /dev/null
+++ b/substrate/frame/support/test/tests/pallet_ui/config_metadata_non_type_info.stderr
@@ -0,0 +1,5 @@
+error: Invalid #[pallet::include_metadata] in #[pallet::config], collected type `MyNonScaleTypeInfo` does not implement `TypeInfo` or `Parameter`
+  --> tests/pallet_ui/config_metadata_non_type_info.rs:28:4
+   |
+28 |         #[pallet::include_metadata]
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/substrate/frame/support/test/tests/pallet_ui/config_metadata_on_constants.rs b/substrate/frame/support/test/tests/pallet_ui/config_metadata_on_constants.rs
new file mode 100644
index 0000000000000000000000000000000000000000..5452479b76e789a77c2c6f34fc88ff0db939ea54
--- /dev/null
+++ b/substrate/frame/support/test/tests/pallet_ui/config_metadata_on_constants.rs
@@ -0,0 +1,40 @@
+// This file is part of Substrate.
+
+// Copyright (C) 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.
+
+#[frame_support::pallet]
+mod pallet {
+	use frame_support::pallet_prelude::*;
+	use frame_system::pallet_prelude::*;
+
+	#[pallet::config]
+	pub trait Config: frame_system::Config {
+		#[pallet::constant]
+       	#[pallet::include_metadata]
+		type MyGetParam2: Get<u32>;
+	}
+
+	#[pallet::pallet]
+	pub struct Pallet<T>(core::marker::PhantomData<T>);
+
+	#[pallet::hooks]
+	impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {}
+
+	#[pallet::call]
+	impl<T: Config> Pallet<T> {}
+}
+
+fn main() {}
diff --git a/substrate/frame/support/test/tests/pallet_ui/config_metadata_on_constants.stderr b/substrate/frame/support/test/tests/pallet_ui/config_metadata_on_constants.stderr
new file mode 100644
index 0000000000000000000000000000000000000000..eb943158f38acb5807bec5b773968a3c15430e4e
--- /dev/null
+++ b/substrate/frame/support/test/tests/pallet_ui/config_metadata_on_constants.stderr
@@ -0,0 +1,5 @@
+error: Invalid #[pallet::include_metadata]: conflict with #[pallet::constant]. Pallet constant already collect the metadata for the type.
+  --> tests/pallet_ui/config_metadata_on_constants.rs:26:10
+   |
+26 |            #[pallet::include_metadata]
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/substrate/frame/support/test/tests/pallet_ui/config_metadata_on_events.rs b/substrate/frame/support/test/tests/pallet_ui/config_metadata_on_events.rs
new file mode 100644
index 0000000000000000000000000000000000000000..d91f86771bf6de497b82098483df578874651feb
--- /dev/null
+++ b/substrate/frame/support/test/tests/pallet_ui/config_metadata_on_events.rs
@@ -0,0 +1,43 @@
+// This file is part of Substrate.
+
+// Copyright (C) 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.
+
+#[frame_support::pallet]
+mod pallet {
+	use frame_support::pallet_prelude::*;
+	use frame_system::pallet_prelude::*;
+
+	#[pallet::config(with_default)]
+	pub trait Config: frame_system::Config {
+		#[pallet::no_default_bounds]
+		#[pallet::include_metadata]
+		type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
+
+		#[pallet::constant]
+		type MyGetParam2: Get<u32>;
+	}
+
+	#[pallet::pallet]
+	pub struct Pallet<T>(core::marker::PhantomData<T>);
+
+	#[pallet::hooks]
+	impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {}
+
+	#[pallet::call]
+	impl<T: Config> Pallet<T> {}
+}
+
+fn main() {}
diff --git a/substrate/frame/support/test/tests/pallet_ui/config_metadata_on_events.stderr b/substrate/frame/support/test/tests/pallet_ui/config_metadata_on_events.stderr
new file mode 100644
index 0000000000000000000000000000000000000000..15132ccce04cf610243b6c6b4189fd3ee54033bc
--- /dev/null
+++ b/substrate/frame/support/test/tests/pallet_ui/config_metadata_on_events.stderr
@@ -0,0 +1,5 @@
+error: Invalid #[pallet::include_metadata] for `type RuntimeEvent`. The associated type `RuntimeEvent` is already collected in the metadata.
+  --> tests/pallet_ui/config_metadata_on_events.rs:26:4
+   |
+26 |         #[pallet::include_metadata]
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/substrate/frame/support/test/tests/pallet_ui/no_default_but_missing_with_default.stderr b/substrate/frame/support/test/tests/pallet_ui/no_default_but_missing_with_default.stderr
index e8df28a3046f23289bb50499d3b334028ac9bcc3..1b066bbe9fb8cc3cc50784a29470555beb7dcb0e 100644
--- a/substrate/frame/support/test/tests/pallet_ui/no_default_but_missing_with_default.stderr
+++ b/substrate/frame/support/test/tests/pallet_ui/no_default_but_missing_with_default.stderr
@@ -1,4 +1,4 @@
-error: `#[pallet:no_default]` can only be used if `#[pallet::config(with_default)]` has been specified
+error: `#[pallet::no_default]` can only be used if `#[pallet::config(with_default)]` has been specified
   --> tests/pallet_ui/no_default_but_missing_with_default.rs:26:4
    |
 26 |         #[pallet::no_default]
diff --git a/substrate/frame/support/test/tests/pallet_ui/pass/config_multiple_attr.rs b/substrate/frame/support/test/tests/pallet_ui/pass/config_multiple_attr.rs
new file mode 100644
index 0000000000000000000000000000000000000000..c016c52181cf9140e1c51136bb4b2a0d913735ad
--- /dev/null
+++ b/substrate/frame/support/test/tests/pallet_ui/pass/config_multiple_attr.rs
@@ -0,0 +1,32 @@
+// This file is part of Substrate.
+
+// Copyright (C) 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.
+
+#[frame_support::pallet]
+mod pallet {
+	use frame_support::pallet_prelude::*;
+
+	#[pallet::config(with_default, without_automatic_metadata)]
+	pub trait Config: frame_system::Config {
+		#[pallet::constant]
+		type MyGetParam2: Get<Self::AccountId>;
+	}
+
+	#[pallet::pallet]
+	pub struct Pallet<T>(_);
+}
+
+fn main() {}
diff --git a/substrate/frame/support/test/tests/pallet_ui/pass/config_without_metadata.rs b/substrate/frame/support/test/tests/pallet_ui/pass/config_without_metadata.rs
new file mode 100644
index 0000000000000000000000000000000000000000..c9f5244d734528347e487a5177a5bb678b32a35b
--- /dev/null
+++ b/substrate/frame/support/test/tests/pallet_ui/pass/config_without_metadata.rs
@@ -0,0 +1,32 @@
+// This file is part of Substrate.
+
+// Copyright (C) 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.
+
+#[frame_support::pallet]
+mod pallet {
+	use frame_support::pallet_prelude::*;
+
+	#[pallet::config(without_automatic_metadata)]
+	pub trait Config: frame_system::Config {
+		#[pallet::constant]
+		type MyGetParam2: Get<Self::AccountId>;
+	}
+
+	#[pallet::pallet]
+	pub struct Pallet<T>(_);
+}
+
+fn main() {}
diff --git a/substrate/primitives/metadata-ir/src/types.rs b/substrate/primitives/metadata-ir/src/types.rs
index 4ebe8c25a6757e8877e5a01ae21b789265c6cf37..da4f5d7f3711cdf6b85773daa0b90469129b0d49 100644
--- a/substrate/primitives/metadata-ir/src/types.rs
+++ b/substrate/primitives/metadata-ir/src/types.rs
@@ -133,6 +133,8 @@ pub struct PalletMetadataIR<T: Form = MetaForm> {
 	pub constants: Vec<PalletConstantMetadataIR<T>>,
 	/// Pallet error metadata.
 	pub error: Option<PalletErrorMetadataIR<T>>,
+	/// Config's trait associated types.
+	pub associated_types: Vec<PalletAssociatedTypeMetadataIR<T>>,
 	/// Define the index of the pallet, this index will be used for the encoding of pallet event,
 	/// call and origin variants.
 	pub index: u8,
@@ -153,6 +155,7 @@ impl IntoPortable for PalletMetadataIR {
 			event: self.event.map(|event| event.into_portable(registry)),
 			constants: registry.map_into_portable(self.constants),
 			error: self.error.map(|error| error.into_portable(registry)),
+			associated_types: registry.map_into_portable(self.associated_types),
 			index: self.index,
 			docs: registry.map_into_portable(self.docs),
 			deprecation_info: self.deprecation_info.into_portable(registry),
@@ -197,6 +200,29 @@ impl IntoPortable for ExtrinsicMetadataIR {
 	}
 }
 
+/// Metadata of a pallet's associated type.
+#[derive(Clone, PartialEq, Eq, Encode, Debug)]
+pub struct PalletAssociatedTypeMetadataIR<T: Form = MetaForm> {
+	/// The name of the associated type.
+	pub name: T::String,
+	/// The type of the associated type.
+	pub ty: T::Type,
+	/// The documentation of the associated type.
+	pub docs: Vec<T::String>,
+}
+
+impl IntoPortable for PalletAssociatedTypeMetadataIR {
+	type Output = PalletAssociatedTypeMetadataIR<PortableForm>;
+
+	fn into_portable(self, registry: &mut Registry) -> Self::Output {
+		PalletAssociatedTypeMetadataIR {
+			name: self.name.into_portable(registry),
+			ty: registry.register_type(&self.ty),
+			docs: registry.map_into_portable(self.docs),
+		}
+	}
+}
+
 /// Metadata of an extrinsic's signed extension.
 #[derive(Clone, PartialEq, Eq, Encode, Debug)]
 pub struct SignedExtensionMetadataIR<T: Form = MetaForm> {