diff --git a/core/lib/Drupal/Core/Breadcrumb/BreadcrumbManager.php b/core/lib/Drupal/Core/Breadcrumb/BreadcrumbManager.php
index 1c745ed6a2620f3915317bb0012fc514f1353bf0..0a75387dd1d83b6781dc93322b28b9c6477c3c2b 100644
--- a/core/lib/Drupal/Core/Breadcrumb/BreadcrumbManager.php
+++ b/core/lib/Drupal/Core/Breadcrumb/BreadcrumbManager.php
@@ -83,16 +83,18 @@ public function build(RouteMatchInterface $route_match) {
       }
 
       $breadcrumb = $builder->build($route_match);
-
       if ($breadcrumb instanceof Breadcrumb) {
         $context['builder'] = $builder;
-        $breadcrumb->addCacheableDependency($cacheable_metadata);
         break;
       }
       else {
         throw new \UnexpectedValueException('Invalid breadcrumb returned by ' . get_class($builder) . '::build().');
       }
     }
+
+    // Ensure all collected cacheability is applied.
+    $breadcrumb->addCacheableDependency($cacheable_metadata);
+
     // Allow modules to alter the breadcrumb.
     $this->moduleHandler->alter('system_breadcrumb', $breadcrumb, $route_match, $context);
 
diff --git a/core/modules/system/tests/modules/menu_test/menu_test.routing.yml b/core/modules/system/tests/modules/menu_test/menu_test.routing.yml
index 4f3c9e28b1c5a7ce9d7b1ef64e07f6bedad34127..f427fe5fe87e2b2a8950255b451793b0c8781419 100644
--- a/core/modules/system/tests/modules/menu_test/menu_test.routing.yml
+++ b/core/modules/system/tests/modules/menu_test/menu_test.routing.yml
@@ -577,3 +577,11 @@ menu_test.breadcrumb3:
     _title: 'Normal title'
   requirements:
     _access: 'TRUE'
+
+menu_test.skippable-breadcrumb:
+  path: '/menu-test/skippable-breadcrumb'
+  defaults:
+    _controller: '\Drupal\menu_test\Controller\MenuTestController::menuTestCallback'
+    _title: 'Normal title'
+  requirements:
+    _access: 'TRUE'
diff --git a/core/modules/system/tests/modules/menu_test/src/MenuTestServiceProvider.php b/core/modules/system/tests/modules/menu_test/src/MenuTestServiceProvider.php
new file mode 100644
index 0000000000000000000000000000000000000000..f6aad34ecf1834fba039782fa86a2f49dcb95c07
--- /dev/null
+++ b/core/modules/system/tests/modules/menu_test/src/MenuTestServiceProvider.php
@@ -0,0 +1,28 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\menu_test;
+
+use Drupal\Core\DependencyInjection\ContainerBuilder;
+use Drupal\Core\DependencyInjection\ServiceModifierInterface;
+use Symfony\Component\DependencyInjection\Reference;
+
+/**
+ * Decorate core's default path-based breadcrumb builder when it is available.
+ */
+class MenuTestServiceProvider implements ServiceModifierInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function alter(ContainerBuilder $container): void {
+    if ($container->has('system.breadcrumb.default')) {
+      $container->register('menu_test.breadcrumb.default', SkippablePathBasedBreadcrumbBuilder::class)
+        ->setDecoratedService('system.breadcrumb.default')
+        ->addArgument(new Reference('menu_test.breadcrumb.default.inner'))
+        ->addArgument(new Reference('request_stack'));
+    }
+  }
+
+}
diff --git a/core/modules/system/tests/modules/menu_test/src/SkippablePathBasedBreadcrumbBuilder.php b/core/modules/system/tests/modules/menu_test/src/SkippablePathBasedBreadcrumbBuilder.php
new file mode 100644
index 0000000000000000000000000000000000000000..fc075042ad6edaac4ae907fb97673c5d55acb932
--- /dev/null
+++ b/core/modules/system/tests/modules/menu_test/src/SkippablePathBasedBreadcrumbBuilder.php
@@ -0,0 +1,40 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\menu_test;
+
+use Drupal\Core\Breadcrumb\Breadcrumb;
+use Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface;
+use Drupal\Core\Cache\CacheableMetadata;
+use Drupal\Core\Routing\RouteMatchInterface;
+use Symfony\Component\HttpFoundation\RequestStack;
+
+/**
+ * A path-based breadcrumb builder can be skipped from applying.
+ */
+class SkippablePathBasedBreadcrumbBuilder implements BreadcrumbBuilderInterface {
+
+  public function __construct(
+    protected BreadcrumbBuilderInterface $pathBasedBreadcrumbBuilder,
+    protected RequestStack $requestStack,
+  ) {}
+
+  /**
+   * {@inheritdoc}
+   */
+  public function applies(RouteMatchInterface $route_match, ?CacheableMetadata $cacheable_metadata = NULL): bool {
+    $query_arg = 'menu_test_skip_breadcrumbs';
+    $cacheable_metadata?->addCacheContexts(['url.query_args:' . $query_arg]);
+    // Apply unless the query argument is present.
+    return !$this->requestStack->getCurrentRequest()->query->has($query_arg);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function build(RouteMatchInterface $route_match): Breadcrumb {
+    return $this->pathBasedBreadcrumbBuilder->build($route_match);
+  }
+
+}
diff --git a/core/modules/system/tests/src/Functional/Menu/BreadcrumbTest.php b/core/modules/system/tests/src/Functional/Menu/BreadcrumbTest.php
index 1e8b89fff2f251a438a789231e02c16510a310c5..4b2fb36ab24c10c4ee74ffe5e1fcb197e1d08fea 100644
--- a/core/modules/system/tests/src/Functional/Menu/BreadcrumbTest.php
+++ b/core/modules/system/tests/src/Functional/Menu/BreadcrumbTest.php
@@ -388,6 +388,15 @@ public function testBreadCrumbs(): void {
     $this->drupalGet('menu-test/breadcrumb1/breadcrumb2/breadcrumb3');
     $this->assertSession()->responseContains('<script>alert(12);</script>');
     $this->assertSession()->assertEscaped('<script>alert(123);</script>');
+
+    // Assert that the breadcrumb cacheability is respected after not applying.
+    $this->assertBreadcrumb(Url::fromRoute('menu_test.skippable-breadcrumb', [], [
+      'query' => [
+        'menu_test_skip_breadcrumbs' => 'yes',
+      ],
+    ]), []);
+    $trail = $home + ['menu-test' => 'Menu test root'];
+    $this->assertBreadcrumb(Url::fromRoute('menu_test.skippable-breadcrumb'), $trail);
   }
 
   /**