diff --git a/core/lib/Drupal/Core/Breadcrumb/Breadcrumb.php b/core/lib/Drupal/Core/Breadcrumb/Breadcrumb.php
index 1418807..c575364 100644
--- a/core/lib/Drupal/Core/Breadcrumb/Breadcrumb.php
+++ b/core/lib/Drupal/Core/Breadcrumb/Breadcrumb.php
@@ -8,6 +8,7 @@
 namespace Drupal\Core\Breadcrumb;
 
 use Drupal\Core\Cache\CacheableMetadata;
+use Drupal\Core\Cache\RefinableCacheableDependencyInterface;
 use Drupal\Core\Link;
 
 /**
@@ -15,7 +16,21 @@
  *
  * @todo implement RenderableInterface once https://www.drupal.org/node/2529560 lands.
  */
-class Breadcrumb extends CacheableMetadata {
+class Breadcrumb implements RefinableCacheableDependencyInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function __construct(RefinableCacheableDependencyInterface $cacheable_metadata = NULL) {
+    $this->cacheableMetadata = $cacheable_metadata ?: new CacheableMetadata();
+  }
+
+  /**
+   * The wrapped cacheable metadata.
+   *
+   * @var \Drupal\Core\Cache\RefinableCacheableDependencyInterface
+   */
+  protected $cacheableMetadata;
 
   /**
    * An ordered list of links for the breadcrumb.
@@ -68,4 +83,78 @@ public function addLink(Link $link) {
     return $this;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getCacheContexts() {
+    return $this->cacheableMetadata->getCacheContexts();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getCacheTags() {
+    return $this->cacheableMetadata->getCacheTags();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getCacheMaxAge() {
+    return $this->cacheableMetadata->getCacheMaxAge();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function addCacheContexts(array $cache_contexts) {
+    return $this->cacheableMetadata->addCacheContexts($cache_contexts);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function addCacheTags(array $cache_tags) {
+    return $this->cacheableMetadata->addCacheTags($cache_tags);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function mergeCacheMaxAge($max_age) {
+    return $this->cacheableMetadata->setCacheMaxAge($max_age);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function addCacheableDependency($other_object) {
+    return $this->cacheableMetadata->addCacheableDependency($other_object);
+  }
+
+  /**
+   * Returns a render array representation of the object.
+   *
+   * @return mixed[]
+   *   A render array.
+   *
+   * @todo implement RenderableInterface once https://www.drupal.org/node/2529560 lands.
+   */
+  public function toRenderable() {
+    $build = [
+      '#cache' => [
+        'contexts' => $this->cacheableMetadata->getCacheContexts(),
+        'tags' => $this->cacheableMetadata->getCacheTags(),
+        'max-age' => $this->getCacheMaxAge(),
+      ],
+    ];
+    if ($this->links) {
+      $build += [
+        '#theme' => 'breadcrumb',
+        '#links' => $this->links,
+      ];
+    }
+    return $build;
+  }
+
 }
diff --git a/core/modules/book/src/BookBreadcrumbBuilder.php b/core/modules/book/src/BookBreadcrumbBuilder.php
index b1ece44..4bef0e3 100644
--- a/core/modules/book/src/BookBreadcrumbBuilder.php
+++ b/core/modules/book/src/BookBreadcrumbBuilder.php
@@ -96,7 +96,7 @@ public function build(RouteMatchInterface $route_match) {
       }
     }
     $breadcrumb->setLinks($links);
-    $breadcrumb->setCacheContexts(['route.book_navigation']);
+    $breadcrumb->addCacheContexts(['route.book_navigation']);
     return $breadcrumb;
   }
 
diff --git a/core/modules/comment/src/CommentBreadcrumbBuilder.php b/core/modules/comment/src/CommentBreadcrumbBuilder.php
index 873b569..d4f0747 100644
--- a/core/modules/comment/src/CommentBreadcrumbBuilder.php
+++ b/core/modules/comment/src/CommentBreadcrumbBuilder.php
@@ -49,7 +49,7 @@ public function applies(RouteMatchInterface $route_match) {
    */
   public function build(RouteMatchInterface $route_match) {
     $breadcrumb = new Breadcrumb();
-    $breadcrumb->setCacheContexts(['route']);
+    $breadcrumb->addCacheContexts(['route']);
     $breadcrumb->addLink(Link::createFromRoute($this->t('Home'), '<front>'));
 
     $entity = $route_match->getParameter('entity');
diff --git a/core/modules/forum/src/Breadcrumb/ForumBreadcrumbBuilderBase.php b/core/modules/forum/src/Breadcrumb/ForumBreadcrumbBuilderBase.php
index f5fa2a8..d770b3a 100644
--- a/core/modules/forum/src/Breadcrumb/ForumBreadcrumbBuilderBase.php
+++ b/core/modules/forum/src/Breadcrumb/ForumBreadcrumbBuilderBase.php
@@ -67,7 +67,7 @@ public function __construct(EntityManagerInterface $entity_manager, ConfigFactor
    */
   public function build(RouteMatchInterface $route_match) {
     $breadcrumb = new Breadcrumb();
-    $breadcrumb->setCacheContexts(['route']);
+    $breadcrumb->addCacheContexts(['route']);
 
     $links[] = Link::createFromRoute($this->t('Home'), '<front>');
 
diff --git a/core/modules/system/src/PathBasedBreadcrumbBuilder.php b/core/modules/system/src/PathBasedBreadcrumbBuilder.php
index 4acbee2..71b17c6 100644
--- a/core/modules/system/src/PathBasedBreadcrumbBuilder.php
+++ b/core/modules/system/src/PathBasedBreadcrumbBuilder.php
@@ -143,7 +143,7 @@ public function build(RouteMatchInterface $route_match) {
     $exclude['/user'] = TRUE;
     // Because this breadcrumb builder is entirely path-based, vary by the
     // 'url.path' cache context.
-    $breadcrumb->setCacheContexts(['url.path']);
+    $breadcrumb->addCacheContexts(['url.path']);
     while (count($path_elements) > 1) {
       array_pop($path_elements);
       // Copy the path elements for up-casting.
diff --git a/core/modules/system/src/Plugin/Block/SystemBreadcrumbBlock.php b/core/modules/system/src/Plugin/Block/SystemBreadcrumbBlock.php
index 40da616..a863bac 100644
--- a/core/modules/system/src/Plugin/Block/SystemBreadcrumbBlock.php
+++ b/core/modules/system/src/Plugin/Block/SystemBreadcrumbBlock.php
@@ -74,16 +74,7 @@ public static function create(ContainerInterface $container, array $configuratio
    * {@inheritdoc}
    */
   public function build() {
-    $breadcrumb = $this->breadcrumbManager->build($this->routeMatch);
-    if (!empty($breadcrumb)) {
-      // $breadcrumb is expected to be an array of rendered breadcrumb links.
-      $build = [
-        '#theme' => 'breadcrumb',
-        '#links' => $breadcrumb->getLinks(),
-      ];
-      $breadcrumb->applyTo($build);
-      return $build;
-    }
+    return $this->breadcrumbManager->build($this->routeMatch)->toRenderable();
   }
 
 }
diff --git a/core/modules/taxonomy/src/TermBreadcrumbBuilder.php b/core/modules/taxonomy/src/TermBreadcrumbBuilder.php
index c2387c4..4fdfe84 100644
--- a/core/modules/taxonomy/src/TermBreadcrumbBuilder.php
+++ b/core/modules/taxonomy/src/TermBreadcrumbBuilder.php
@@ -78,7 +78,7 @@ public function build(RouteMatchInterface $route_match) {
 
     // This breadcrumb builder is based on a route parameter, and hence it
     // depends on the 'route' cache context.
-    $breadcrumb->setCacheContexts(['route']);
+    $breadcrumb->addCacheContexts(['route']);
 
     return $breadcrumb;
   }
diff --git a/core/tests/Drupal/Tests/Core/Breadcrumb/BreadcrumbManagerTest.php b/core/tests/Drupal/Tests/Core/Breadcrumb/BreadcrumbManagerTest.php
index b91460b..a9f301d 100644
--- a/core/tests/Drupal/Tests/Core/Breadcrumb/BreadcrumbManagerTest.php
+++ b/core/tests/Drupal/Tests/Core/Breadcrumb/BreadcrumbManagerTest.php
@@ -10,6 +10,8 @@
 use Drupal\Core\Breadcrumb\Breadcrumb;
 use Drupal\Core\Breadcrumb\BreadcrumbManager;
 use Drupal\Core\Cache\Cache;
+use Drupal\Core\Cache\Context\CacheContextsManager;
+use Drupal\Core\DependencyInjection\ContainerBuilder;
 use Drupal\Tests\UnitTestCase;
 
 /**
@@ -19,6 +21,13 @@
 class BreadcrumbManagerTest extends UnitTestCase {
 
   /**
+   * The dependency injection container.
+   *
+   * @var \Symfony\Component\DependencyInjection\ContainerBuilder
+   */
+  protected $container;
+
+  /**
    * The breadcrumb object.
    *
    * @var \Drupal\Core\Breadcrumb\Breadcrumb
@@ -46,6 +55,11 @@ protected function setUp() {
     $this->moduleHandler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface');
     $this->breadcrumbManager = new BreadcrumbManager($this->moduleHandler);
     $this->breadcrumb = new Breadcrumb();
+
+    $this->container = new ContainerBuilder();
+    $cache_contexts_manager = $this->prophesize(CacheContextsManager::class)->reveal();
+    $this->container->set('cache_contexts_manager', $cache_contexts_manager);
+    \Drupal::setContainer($this->container);
   }
 
   /**
@@ -71,7 +85,7 @@ public function testBuildWithSingleBuilder() {
     $builder = $this->getMock('Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface');
     $links = array('<a href="/example">Test</a>');
     $this->breadcrumb->setLinks($links);
-    $this->breadcrumb->setCacheContexts(['foo'])->setCacheTags(['bar']);
+    $this->breadcrumb->addCacheContexts(['foo'])->addCacheTags(['bar']);
 
     $builder->expects($this->once())
       ->method('applies')
@@ -108,7 +122,7 @@ public function testBuildWithMultipleApplyingBuilders() {
     $builder2 = $this->getMock('Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface');
     $links2 = array('<a href="/example2">Test2</a>');
     $this->breadcrumb->setLinks($links2);
-    $this->breadcrumb->setCacheContexts(['baz'])->setCacheTags(['qux']);
+    $this->breadcrumb->addCacheContexts(['baz'])->addCacheTags(['qux']);
     $builder2->expects($this->once())
       ->method('applies')
       ->will($this->returnValue(TRUE));
@@ -146,7 +160,7 @@ public function testBuildWithOneNotApplyingBuilders() {
     $builder2 = $this->getMock('Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface');
     $links2 = ['<a href="/example2">Test2</a>'];
     $this->breadcrumb->setLinks($links2);
-    $this->breadcrumb->setCacheContexts(['baz'])->setCacheTags(['qux']);
+    $this->breadcrumb->addCacheContexts(['baz'])->addCacheTags(['qux']);
     $builder2->expects($this->once())
       ->method('applies')
       ->will($this->returnValue(TRUE));
