diff --git a/.gitlab/pipeline/zombienet/polkadot.yml b/.gitlab/pipeline/zombienet/polkadot.yml
index 878f241317a42a102e08e7267a9b5d09c1fc1771..e09be328c81d07cd8d11cde93f02814b34a30475 100644
--- a/.gitlab/pipeline/zombienet/polkadot.yml
+++ b/.gitlab/pipeline/zombienet/polkadot.yml
@@ -379,6 +379,23 @@ zombienet-polkadot-elastic-scaling-slot-based-3cores:
     - unset NEXTEST_SUCCESS_OUTPUT
     - cargo nextest run --archive-file ./artifacts/polkadot-zombienet-tests.tar.zst --no-capture -- elastic_scaling::slot_based_3cores::slot_based_3cores_test
 
+zombienet-polkadot-elastic-scaling-slot-based-12cores:
+  extends:
+    - .zombienet-polkadot-common
+  needs:
+    - job: build-polkadot-zombienet-tests
+      artifacts: true
+  before_script:
+    - !reference [ ".zombienet-polkadot-common", "before_script" ]
+    - export POLKADOT_IMAGE="${ZOMBIENET_INTEGRATION_TEST_IMAGE}"
+    - export CUMULUS_IMAGE="docker.io/paritypr/test-parachain:${PIPELINE_IMAGE_TAG}"
+    - export X_INFRA_INSTANCE=spot # use spot by default
+  script:
+    # we want to use `--no-capture` in zombienet tests.
+    - unset NEXTEST_FAILURE_OUTPUT
+    - unset NEXTEST_SUCCESS_OUTPUT
+    - cargo nextest run --archive-file ./artifacts/polkadot-zombienet-tests.tar.zst --no-capture -- elastic_scaling::slot_based_12cores::slot_based_12cores_test
+
 zombienet-polkadot-elastic-scaling-doesnt-break-parachains:
   extends:
     - .zombienet-polkadot-common
diff --git a/cumulus/client/consensus/aura/src/collators/mod.rs b/cumulus/client/consensus/aura/src/collators/mod.rs
index 66c6086eaf9ee3b2410ad389ae67a603b9311a6d..df775f6c9ec07d00cba1c7aeee60510691ef210a 100644
--- a/cumulus/client/consensus/aura/src/collators/mod.rs
+++ b/cumulus/client/consensus/aura/src/collators/mod.rs
@@ -44,12 +44,13 @@ pub mod lookahead;
 pub mod slot_based;
 
 // This is an arbitrary value which is likely guaranteed to exceed any reasonable
-// limit, as it would correspond to 10 non-included blocks.
+// limit, as it would correspond to 30 non-included blocks.
 //
 // Since we only search for parent blocks which have already been imported,
 // we can guarantee that all imported blocks respect the unincluded segment
-// rules specified by the parachain's runtime and thus will never be too deep.
-const PARENT_SEARCH_DEPTH: usize = 10;
+// rules specified by the parachain's runtime and thus will never be too deep. This is just an extra
+// sanity check.
+const PARENT_SEARCH_DEPTH: usize = 30;
 
 /// Check the `local_validation_code_hash` against the validation code hash in the relay chain
 /// state.
diff --git a/cumulus/test/runtime/Cargo.toml b/cumulus/test/runtime/Cargo.toml
index 71509f82bfe13ab224fcf257f68a1aaa765c528e..711525a297c728e5f721282615b460aa70490d8e 100644
--- a/cumulus/test/runtime/Cargo.toml
+++ b/cumulus/test/runtime/Cargo.toml
@@ -94,4 +94,5 @@ std = [
 ]
 increment-spec-version = []
 elastic-scaling = []
+elastic-scaling-500ms = []
 experimental-ump-signals = ["cumulus-pallet-parachain-system/experimental-ump-signals"]
diff --git a/cumulus/test/runtime/build.rs b/cumulus/test/runtime/build.rs
index 43e60c1074a047ecaeda05838178bac87f857899..99d30ce6dc37257ae1a8aadf3a4f96ad5be97864 100644
--- a/cumulus/test/runtime/build.rs
+++ b/cumulus/test/runtime/build.rs
@@ -39,6 +39,14 @@ fn main() {
 		.import_memory()
 		.set_file_name("wasm_binary_elastic_scaling.rs")
 		.build();
+
+	WasmBuilder::new()
+		.with_current_project()
+		.enable_feature("elastic-scaling-500ms")
+		.enable_feature("experimental-ump-signals")
+		.import_memory()
+		.set_file_name("wasm_binary_elastic_scaling_500ms.rs")
+		.build();
 }
 
 #[cfg(not(feature = "std"))]
diff --git a/cumulus/test/runtime/src/lib.rs b/cumulus/test/runtime/src/lib.rs
index 01ce3427c1f19b21663bd7b940c1fa95e212c48b..09e1361603a08377a8e3fdd2a71968dac8dedec2 100644
--- a/cumulus/test/runtime/src/lib.rs
+++ b/cumulus/test/runtime/src/lib.rs
@@ -27,6 +27,10 @@ pub mod wasm_spec_version_incremented {
 	include!(concat!(env!("OUT_DIR"), "/wasm_binary_spec_version_incremented.rs"));
 }
 
+pub mod elastic_scaling_500ms {
+	#[cfg(feature = "std")]
+	include!(concat!(env!("OUT_DIR"), "/wasm_binary_elastic_scaling_500ms.rs"));
+}
 pub mod elastic_scaling_mvp {
 	#[cfg(feature = "std")]
 	include!(concat!(env!("OUT_DIR"), "/wasm_binary_elastic_scaling_mvp.rs"));
@@ -98,21 +102,21 @@ impl_opaque_keys! {
 /// The para-id used in this runtime.
 pub const PARACHAIN_ID: u32 = 100;
 
-#[cfg(not(feature = "elastic-scaling"))]
-const UNINCLUDED_SEGMENT_CAPACITY: u32 = 4;
-#[cfg(not(feature = "elastic-scaling"))]
-const BLOCK_PROCESSING_VELOCITY: u32 = 1;
-
-#[cfg(feature = "elastic-scaling")]
-const UNINCLUDED_SEGMENT_CAPACITY: u32 = 7;
-#[cfg(feature = "elastic-scaling")]
-const BLOCK_PROCESSING_VELOCITY: u32 = 4;
-
-#[cfg(not(feature = "elastic-scaling"))]
+#[cfg(not(any(feature = "elastic-scaling", feature = "elastic-scaling-500ms")))]
 pub const MILLISECS_PER_BLOCK: u64 = 6000;
-#[cfg(feature = "elastic-scaling")]
+
+#[cfg(all(feature = "elastic-scaling", not(feature = "elastic-scaling-500ms")))]
 pub const MILLISECS_PER_BLOCK: u64 = 2000;
 
+#[cfg(feature = "elastic-scaling-500ms")]
+pub const MILLISECS_PER_BLOCK: u64 = 500;
+
+const BLOCK_PROCESSING_VELOCITY: u32 =
+	RELAY_CHAIN_SLOT_DURATION_MILLIS / (MILLISECS_PER_BLOCK as u32);
+
+// The `+2` shouldn't be needed, https://github.com/paritytech/polkadot-sdk/issues/5260
+const UNINCLUDED_SEGMENT_CAPACITY: u32 = BLOCK_PROCESSING_VELOCITY * 2 + 2;
+
 pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK;
 
 const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000;
diff --git a/cumulus/test/service/src/chain_spec.rs b/cumulus/test/service/src/chain_spec.rs
index 5ebcc14592d74d2585fbc8f6e54f41dd1b0b700d..b59bd7ab46bdbd9fb1591cc6b71a5dae141f0e06 100644
--- a/cumulus/test/service/src/chain_spec.rs
+++ b/cumulus/test/service/src/chain_spec.rs
@@ -117,6 +117,16 @@ pub fn get_elastic_scaling_chain_spec(id: Option<ParaId>) -> ChainSpec {
 	)
 }
 
+/// Get the chain spec for a specific parachain ID.
+pub fn get_elastic_scaling_500ms_chain_spec(id: Option<ParaId>) -> ChainSpec {
+	get_chain_spec_with_extra_endowed(
+		id,
+		Default::default(),
+		cumulus_test_runtime::elastic_scaling_500ms::WASM_BINARY
+			.expect("WASM binary was not built, please build it!"),
+	)
+}
+
 /// Get the chain spec for a specific parachain ID.
 pub fn get_elastic_scaling_mvp_chain_spec(id: Option<ParaId>) -> ChainSpec {
 	get_chain_spec_with_extra_endowed(
diff --git a/cumulus/test/service/src/cli.rs b/cumulus/test/service/src/cli.rs
index e019089e70fe8e8b7b12543d78459a0fed539ff7..7909ffbf7142f3ae34338340fdc6561fc709f22f 100644
--- a/cumulus/test/service/src/cli.rs
+++ b/cumulus/test/service/src/cli.rs
@@ -274,6 +274,12 @@ impl SubstrateCli for TestCollatorCli {
 					2200,
 				)))) as Box<_>
 			},
+			"elastic-scaling-500ms" => {
+				tracing::info!("Using elastic-scaling 500ms chain spec.");
+				Box::new(cumulus_test_service::get_elastic_scaling_500ms_chain_spec(Some(
+					ParaId::from(2300),
+				))) as Box<_>
+			},
 			path => {
 				let chain_spec =
 					cumulus_test_service::chain_spec::ChainSpec::from_json_file(path.into())?;
diff --git a/polkadot/zombienet-sdk-tests/tests/elastic_scaling/mod.rs b/polkadot/zombienet-sdk-tests/tests/elastic_scaling/mod.rs
index 9cfd5db5a096dbd393f84ea4fff7bf2b1df59227..a993e8e27214b649c00e35cbf8e24105a1d1dd60 100644
--- a/polkadot/zombienet-sdk-tests/tests/elastic_scaling/mod.rs
+++ b/polkadot/zombienet-sdk-tests/tests/elastic_scaling/mod.rs
@@ -3,4 +3,5 @@
 
 mod basic_3cores;
 mod doesnt_break_parachains;
+mod slot_based_12cores;
 mod slot_based_3cores;
diff --git a/polkadot/zombienet-sdk-tests/tests/elastic_scaling/slot_based_12cores.rs b/polkadot/zombienet-sdk-tests/tests/elastic_scaling/slot_based_12cores.rs
new file mode 100644
index 0000000000000000000000000000000000000000..4d0e1adad0849a5a695c0a47db33ec7e3fe5378f
--- /dev/null
+++ b/polkadot/zombienet-sdk-tests/tests/elastic_scaling/slot_based_12cores.rs
@@ -0,0 +1,129 @@
+// Copyright (C) Parity Technologies (UK) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+// Test that a parachain that uses a single slot-based collator with elastic scaling can use 12
+// cores in order to achieve 500ms blocks.
+
+use anyhow::anyhow;
+
+use crate::helpers::{
+	assert_finalized_block_height, assert_para_throughput, rococo,
+	rococo::runtime_types::{
+		pallet_broker::coretime_interface::CoreAssignment,
+		polkadot_runtime_parachains::assigner_coretime::PartsOf57600,
+	},
+};
+use polkadot_primitives::Id as ParaId;
+use serde_json::json;
+use subxt::{OnlineClient, PolkadotConfig};
+use subxt_signer::sr25519::dev;
+use zombienet_sdk::NetworkConfigBuilder;
+
+#[tokio::test(flavor = "multi_thread")]
+async fn slot_based_12cores_test() -> Result<(), anyhow::Error> {
+	let _ = env_logger::try_init_from_env(
+		env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, "info"),
+	);
+
+	let images = zombienet_sdk::environment::get_images_from_env();
+
+	let config = NetworkConfigBuilder::new()
+		.with_relaychain(|r| {
+			let r = r
+				.with_chain("rococo-local")
+				.with_default_command("polkadot")
+				.with_default_image(images.polkadot.as_str())
+				.with_default_args(vec![("-lparachain=debug").into()])
+				.with_genesis_overrides(json!({
+					"configuration": {
+						"config": {
+							"scheduler_params": {
+								"num_cores": 11,
+								"max_validators_per_core": 1
+							},
+							"async_backing_params": {
+								"max_candidate_depth": 24,
+								"allowed_ancestry_len": 2
+							}
+						}
+					}
+				}))
+				// Have to set a `with_node` outside of the loop below, so that `r` has the right
+				// type.
+				.with_node(|node| node.with_name("validator-0"));
+
+			(1..12)
+				.fold(r, |acc, i| acc.with_node(|node| node.with_name(&format!("validator-{i}"))))
+		})
+		.with_parachain(|p| {
+			p.with_id(2300)
+				.with_default_command("test-parachain")
+				.with_default_image(images.cumulus.as_str())
+				.with_chain("elastic-scaling-500ms")
+				.with_default_args(vec![
+					("--experimental-use-slot-based").into(),
+					("-lparachain=debug,aura=debug").into(),
+				])
+				.with_collator(|n| n.with_name("collator-elastic"))
+		})
+		.build()
+		.map_err(|e| {
+			let errs = e.into_iter().map(|e| e.to_string()).collect::<Vec<_>>().join(" ");
+			anyhow!("config errs: {errs}")
+		})?;
+
+	let spawn_fn = zombienet_sdk::environment::get_spawn_fn();
+	let network = spawn_fn(config).await?;
+
+	let relay_node = network.get_node("validator-0")?;
+	let para_node = network.get_node("collator-elastic")?;
+
+	let relay_client: OnlineClient<PolkadotConfig> = relay_node.wait_client().await?;
+	let alice = dev::alice();
+
+	// Assign 11 extra cores to the parachain.
+
+	relay_client
+		.tx()
+		.sign_and_submit_then_watch_default(
+			&rococo::tx()
+				.sudo()
+				.sudo(rococo::runtime_types::rococo_runtime::RuntimeCall::Utility(
+					rococo::runtime_types::pallet_utility::pallet::Call::batch {
+						calls: (0..11).map(|idx| rococo::runtime_types::rococo_runtime::RuntimeCall::Coretime(
+                            rococo::runtime_types::polkadot_runtime_parachains::coretime::pallet::Call::assign_core {
+                                core: idx,
+                                begin: 0,
+                                assignment: vec![(CoreAssignment::Task(2300), PartsOf57600(57600))],
+                                end_hint: None
+                            }
+                        )).collect()
+					},
+				)),
+			&alice,
+		)
+		.await?
+		.wait_for_finalized_success()
+		.await?;
+
+	log::info!("11 more cores assigned to the parachain");
+
+	// Expect a backed candidate count of at least 170 in 15 relay chain blocks
+	// (11.33 candidates per para per relay chain block).
+	// Note that only blocks after the first session change and blocks that don't contain a session
+	// change will be counted.
+	assert_para_throughput(
+		&relay_client,
+		15,
+		[(ParaId::from(2300), 170..181)].into_iter().collect(),
+	)
+	.await?;
+
+	// Assert the parachain finalized block height is also on par with the number of backed
+	// candidates.
+	assert_finalized_block_height(&para_node.wait_client().await?, 158..181).await?;
+
+	log::info!("Test finished successfully");
+
+	Ok(())
+}
diff --git a/prdoc/pr_6983.prdoc b/prdoc/pr_6983.prdoc
new file mode 100644
index 0000000000000000000000000000000000000000..fddf831ead12761b4a60742bf77eb79cae19fd16
--- /dev/null
+++ b/prdoc/pr_6983.prdoc
@@ -0,0 +1,17 @@
+title: 'cumulus: bump PARENT_SEARCH_DEPTH to allow for 12-core elastic scaling'
+doc:
+- audience: Node Dev
+  description: |
+    Bumps the PARENT_SEARCH_DEPTH constant to a larger value (30).
+    This is a node-side limit that restricts the number of allowed pending availability candidates when choosing the parent parablock during authoring.
+    This limit is rather redundant, as the parachain runtime already restricts the unincluded segment length to the configured value in the
+    FixedVelocityConsensusHook.
+    For 12 cores, a value of 24 should be enough, but bumped it to 30 to have some extra buffer.
+
+crates:
+- name: cumulus-client-consensus-aura
+  bump: patch
+- name: cumulus-test-runtime
+  bump: minor
+- name: cumulus-test-service
+  bump: minor