diff --git a/core/core.services.yml b/core/core.services.yml
index 4eb462c..511436e 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -58,6 +58,11 @@ services:
     arguments: ['@request_stack']
     tags:
       - { name: cache.context }
+  cache_context.url.path:
+    class: Drupal\Core\Cache\Context\PathCacheContext
+    arguments: ['@request_stack']
+    tags:
+      - { name: cache.context }
   cache_context.url.query_args:
     class: Drupal\Core\Cache\Context\QueryArgsCacheContext
     arguments: ['@request_stack']
diff --git a/core/lib/Drupal/Core/Breadcrumb/Breadcrumb.php b/core/lib/Drupal/Core/Breadcrumb/Breadcrumb.php
new file mode 100644
index 0000000..1a38f8b
--- /dev/null
+++ b/core/lib/Drupal/Core/Breadcrumb/Breadcrumb.php
@@ -0,0 +1,62 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Breadcrumb\Breadcrumb.
+ */
+
+namespace Drupal\Core\Breadcrumb;
+
+use Drupal\Core\Cache\CacheableMetadata;
+use Drupal\Core\Link;
+
+/**
+ * Used to return generated breadcrumbs with associated cacheability metadata.
+ */
+class Breadcrumb extends CacheableMetadata {
+
+  /**
+   * An ordered list of links for the breadcrumb.
+   *
+   * @var \Drupal\Core\Link[]
+   */
+  protected $links = [];
+
+  /**
+   * Gets the breadcrumb links.
+   *
+   * @return \Drupal\Core\Link[]
+   */
+  public function getLinks() {
+    return $this->links;
+  }
+
+  /**
+   * Sets the breadcrumb links.
+   *
+   * @param \Drupal\Core\Link[] $links
+   *   The breadcrumb links.
+   *
+   * @return $this
+   */
+  public function setLinks(array $links) {
+    $this->links = $links;
+
+    return $this;
+  }
+
+  /**
+   * Appends a link to the end of the ordered list of breadcrumb links.
+   *
+   * @param \Drupal\Core\Link $link
+   *   The link appended to the breadcrumb.
+   *
+   * @return $this
+   */
+  public function addLink(Link $link) {
+    $this->links[] = $link;
+
+    return $this;
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Breadcrumb/BreadcrumbBuilderInterface.php b/core/lib/Drupal/Core/Breadcrumb/BreadcrumbBuilderInterface.php
index ebdfa55..e566f54 100644
--- a/core/lib/Drupal/Core/Breadcrumb/BreadcrumbBuilderInterface.php
+++ b/core/lib/Drupal/Core/Breadcrumb/BreadcrumbBuilderInterface.php
@@ -32,9 +32,8 @@ public function applies(RouteMatchInterface $route_match);
    * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
    *   The current route match.
    *
-   * @return \Drupal\Core\Link[]
-   *   An array of links for the breadcrumb. Returning an empty array will
-   *   suppress all breadcrumbs.
+   * @return \Drupal\Core\Breadcrumb\Breadcrumb
+   *   A breadcrumb.
    */
   public function build(RouteMatchInterface $route_match);
 
diff --git a/core/lib/Drupal/Core/Breadcrumb/BreadcrumbManager.php b/core/lib/Drupal/Core/Breadcrumb/BreadcrumbManager.php
index 0015bf3..0513fcb 100644
--- a/core/lib/Drupal/Core/Breadcrumb/BreadcrumbManager.php
+++ b/core/lib/Drupal/Core/Breadcrumb/BreadcrumbManager.php
@@ -75,21 +75,24 @@ public function applies(RouteMatchInterface $route_match) {
    * {@inheritdoc}
    */
   public function build(RouteMatchInterface $route_match) {
-    $breadcrumb = array();
+    // Without builders return early.
+    $sorted_builders = $this->getSortedBuilders();
+    if (empty($sorted_builders)) {
+      return new Breadcrumb();
+    }
+
     $context = array('builder' => NULL);
     // Call the build method of registered breadcrumb builders,
     // until one of them returns an array.
-    foreach ($this->getSortedBuilders() as $builder) {
+    foreach ($sorted_builders as $builder) {
       if (!$builder->applies($route_match)) {
         // The builder does not apply, so we continue with the other builders.
         continue;
       }
 
-      $build = $builder->build($route_match);
+      $breadcrumb = $builder->build($route_match);
 
-      if (is_array($build)) {
-        // The builder returned an array of breadcrumb links.
-        $breadcrumb = $build;
+      if ($breadcrumb instanceof Breadcrumb) {
         $context['builder'] = $builder;
         break;
       }
@@ -99,7 +102,7 @@ public function build(RouteMatchInterface $route_match) {
     }
     // Allow modules to alter the breadcrumb.
     $this->moduleHandler->alter('system_breadcrumb', $breadcrumb, $route_match, $context);
-    // Fall back to an empty breadcrumb.
+
     return $breadcrumb;
   }
 
diff --git a/core/lib/Drupal/Core/Cache/Context/PathCacheContext.php b/core/lib/Drupal/Core/Cache/Context/PathCacheContext.php
new file mode 100644
index 0000000..d4c3eee
--- /dev/null
+++ b/core/lib/Drupal/Core/Cache/Context/PathCacheContext.php
@@ -0,0 +1,50 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Cache\Context\PathCacheContext.
+ */
+
+namespace Drupal\Core\Cache\Context;
+
+use Drupal\Core\Cache\CacheableMetadata;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+use Drupal\Core\Cache\Context\RequestStackCacheContextBase;
+
+/**
+ * Defines the PathCacheContext service, for "per URL path" caching.
+ *
+ * Cache context ID: 'url.path'.
+ *
+ * (This allows for caching relative URLs.)
+ *
+ * @see \Symfony\Component\HttpFoundation\Request::getBasePath()
+ * @see \Symfony\Component\HttpFoundation\Request::getPathInfo()
+ */
+class PathCacheContext extends RequestStackCacheContextBase implements CacheContextInterface {
+
+  use StringTranslationTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getLabel() {
+    return t('Path');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getContext() {
+    $request = $this->requestStack->getCurrentRequest();
+    return $request->getBasePath() . $request->getPathInfo();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getCacheableMetadata() {
+    return new CacheableMetadata();
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Menu/menu.api.php b/core/lib/Drupal/Core/Menu/menu.api.php
index 8550fc5..29e7eeb 100644
--- a/core/lib/Drupal/Core/Menu/menu.api.php
+++ b/core/lib/Drupal/Core/Menu/menu.api.php
@@ -546,12 +546,8 @@ function hook_contextual_links_plugins_alter(array &$contextual_links) {
 /**
  * Perform alterations to the breadcrumb built by the BreadcrumbManager.
  *
- * @param array $breadcrumb
- *   An array of breadcrumb link a tags, returned by the breadcrumb manager
- *   build method, for example
- *   @code
- *     array('<a href="/">Home</a>');
- *   @endcode
+ * @param \Drupal\Core\Breadcrumb\Breadcrumb $breadcrumb
+ *   A breadcrumb object returned by BreadcrumbBuilderInterface::build().
  * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
  *   The current route match.
  * @param array $context
@@ -562,9 +558,9 @@ function hook_contextual_links_plugins_alter(array &$contextual_links) {
  *
  * @ingroup menu
  */
-function hook_system_breadcrumb_alter(array &$breadcrumb, \Drupal\Core\Routing\RouteMatchInterface $route_match, array $context) {
+function hook_system_breadcrumb_alter(Drupal\Core\Breadcrumb\Breadcrumb &$breadcrumb, \Drupal\Core\Routing\RouteMatchInterface $route_match, array $context) {
   // Add an item to the end of the breadcrumb.
-  $breadcrumb[] = Drupal::l(t('Text'), 'example_route_name');
+  $breadcrumb->addLink(Drupal::l(t('Text'), 'example_route_name'));
 }
 
 /**
diff --git a/core/modules/book/book.services.yml b/core/modules/book/book.services.yml
index 0a022a7..06affbb 100644
--- a/core/modules/book/book.services.yml
+++ b/core/modules/book/book.services.yml
@@ -26,6 +26,8 @@ services:
   cache_context.route.book_navigation:
     class: Drupal\book\Cache\BookNavigationCacheContext
     arguments: ['@request_stack']
+    calls:
+      - [setContainer, ['@service_container']]
     tags:
       - { name: cache.context}
 
diff --git a/core/modules/book/src/BookBreadcrumbBuilder.php b/core/modules/book/src/BookBreadcrumbBuilder.php
index be0e63a..b1ece44 100644
--- a/core/modules/book/src/BookBreadcrumbBuilder.php
+++ b/core/modules/book/src/BookBreadcrumbBuilder.php
@@ -8,6 +8,7 @@
 namespace Drupal\book;
 
 use Drupal\Core\Access\AccessManagerInterface;
+use Drupal\Core\Breadcrumb\Breadcrumb;
 use Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface;
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Link;
@@ -72,6 +73,8 @@ public function applies(RouteMatchInterface $route_match) {
    */
   public function build(RouteMatchInterface $route_match) {
     $book_nids = array();
+    $breadcrumb = new Breadcrumb();
+
     $links = array(Link::createFromRoute($this->t('Home'), '<front>'));
     $book = $route_match->getParameter('node')->book;
     $depth = 1;
@@ -92,7 +95,9 @@ public function build(RouteMatchInterface $route_match) {
         $depth++;
       }
     }
-    return $links;
+    $breadcrumb->setLinks($links);
+    $breadcrumb->setCacheContexts(['route.book_navigation']);
+    return $breadcrumb;
   }
 
 }
diff --git a/core/modules/comment/src/CommentBreadcrumbBuilder.php b/core/modules/comment/src/CommentBreadcrumbBuilder.php
index 8bc2f25..873b569 100644
--- a/core/modules/comment/src/CommentBreadcrumbBuilder.php
+++ b/core/modules/comment/src/CommentBreadcrumbBuilder.php
@@ -8,6 +8,7 @@
 namespace Drupal\comment;
 
 use Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface;
+use Drupal\Core\Breadcrumb\Breadcrumb;
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Link;
 use Drupal\Core\Routing\RouteMatchInterface;
@@ -47,16 +48,20 @@ public function applies(RouteMatchInterface $route_match) {
    * {@inheritdoc}
    */
   public function build(RouteMatchInterface $route_match) {
-    $breadcrumb = [Link::createFromRoute($this->t('Home'), '<front>')];
+    $breadcrumb = new Breadcrumb();
+    $breadcrumb->setCacheContexts(['route']);
+    $breadcrumb->addLink(Link::createFromRoute($this->t('Home'), '<front>'));
 
     $entity = $route_match->getParameter('entity');
-    $breadcrumb[] = new Link($entity->label(), $entity->urlInfo());
+    $breadcrumb->addLink(new Link($entity->label(), $entity->urlInfo()));
+    $breadcrumb->addCacheableDependency($entity);
 
     if (($pid = $route_match->getParameter('pid')) && ($comment = $this->storage->load($pid))) {
       /** @var \Drupal\comment\CommentInterface $comment */
+      $breadcrumb->addCacheableDependency($comment);
       // Display link to parent comment.
       // @todo Clean-up permalink in https://www.drupal.org/node/2198041
-      $breadcrumb[] = new Link($comment->getSubject(), $comment->urlInfo());
+      $breadcrumb->addLink(new Link($comment->getSubject(), $comment->urlInfo()));
     }
 
     return $breadcrumb;
diff --git a/core/modules/forum/src/Breadcrumb/ForumBreadcrumbBuilderBase.php b/core/modules/forum/src/Breadcrumb/ForumBreadcrumbBuilderBase.php
index f595ee8..f5fa2a8 100644
--- a/core/modules/forum/src/Breadcrumb/ForumBreadcrumbBuilderBase.php
+++ b/core/modules/forum/src/Breadcrumb/ForumBreadcrumbBuilderBase.php
@@ -8,6 +8,7 @@
 namespace Drupal\forum\Breadcrumb;
 
 use Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface;
+use Drupal\Core\Breadcrumb\Breadcrumb;
 use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Link;
@@ -65,14 +66,18 @@ public function __construct(EntityManagerInterface $entity_manager, ConfigFactor
    * {@inheritdoc}
    */
   public function build(RouteMatchInterface $route_match) {
-    $breadcrumb[] = Link::createFromRoute($this->t('Home'), '<front>');
+    $breadcrumb = new Breadcrumb();
+    $breadcrumb->setCacheContexts(['route']);
+
+    $links[] = Link::createFromRoute($this->t('Home'), '<front>');
 
     $vocabulary = $this->entityManager
       ->getStorage('taxonomy_vocabulary')
       ->load($this->config->get('vocabulary'));
-    $breadcrumb[] = Link::createFromRoute($vocabulary->label(), 'forum.index');
+    $breadcrumb->addCacheableDependency($vocabulary);
+    $links[] = Link::createFromRoute($vocabulary->label(), 'forum.index');
 
-    return $breadcrumb;
+    return $breadcrumb->setLinks($links);
   }
 
 }
diff --git a/core/modules/forum/src/Breadcrumb/ForumListingBreadcrumbBuilder.php b/core/modules/forum/src/Breadcrumb/ForumListingBreadcrumbBuilder.php
index 9d63772..5f52f2d 100644
--- a/core/modules/forum/src/Breadcrumb/ForumListingBreadcrumbBuilder.php
+++ b/core/modules/forum/src/Breadcrumb/ForumListingBreadcrumbBuilder.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\forum\Breadcrumb;
 
+use Drupal\Core\Breadcrumb\Breadcrumb;
 use Drupal\Core\Link;
 use Drupal\Core\Routing\RouteMatchInterface;
 
@@ -27,19 +28,26 @@ public function applies(RouteMatchInterface $route_match) {
    */
   public function build(RouteMatchInterface $route_match) {
     $breadcrumb = parent::build($route_match);
+    $breadcrumb->addCacheContexts(['route']);
 
     // Add all parent forums to breadcrumbs.
-    $term_id = $route_match->getParameter('taxonomy_term')->id();
+    /** @var \Drupal\Taxonomy\TermInterface $term */
+    $term = $route_match->getParameter('taxonomy_term');
+    $term_id = $term->id();
+    $breadcrumb->addCacheableDependency($term);
+
     $parents = $this->forumManager->getParents($term_id);
     if ($parents) {
       foreach (array_reverse($parents) as $parent) {
         if ($parent->id() != $term_id) {
-          $breadcrumb[] = Link::createFromRoute($parent->label(), 'forum.page', array(
+          $breadcrumb->addCacheableDependency($parent);
+          $breadcrumb->addLink(Link::createFromRoute($parent->label(), 'forum.page', array(
             'taxonomy_term' => $parent->id(),
-          ));
+          )));
         }
       }
     }
+
     return $breadcrumb;
   }
 
diff --git a/core/modules/forum/src/Breadcrumb/ForumNodeBreadcrumbBuilder.php b/core/modules/forum/src/Breadcrumb/ForumNodeBreadcrumbBuilder.php
index 090f0ea..09923f3 100644
--- a/core/modules/forum/src/Breadcrumb/ForumNodeBreadcrumbBuilder.php
+++ b/core/modules/forum/src/Breadcrumb/ForumNodeBreadcrumbBuilder.php
@@ -29,18 +29,20 @@ public function applies(RouteMatchInterface $route_match) {
    */
   public function build(RouteMatchInterface $route_match) {
     $breadcrumb = parent::build($route_match);
+    $breadcrumb->addCacheContexts(['route']);
 
     $parents = $this->forumManager->getParents($route_match->getParameter('node')->forum_tid);
     if ($parents) {
       $parents = array_reverse($parents);
       foreach ($parents as $parent) {
-        $breadcrumb[] = Link::createFromRoute($parent->label(), 'forum.page',
+        $breadcrumb->addLink(Link::createFromRoute($parent->label(), 'forum.page',
           array(
             'taxonomy_term' => $parent->id(),
           )
-        );
+        ));
       }
     }
+
     return $breadcrumb;
   }
 
diff --git a/core/modules/forum/tests/src/Unit/Breadcrumb/ForumBreadcrumbBuilderBaseTest.php b/core/modules/forum/tests/src/Unit/Breadcrumb/ForumBreadcrumbBuilderBaseTest.php
index da7ff11..e171f53 100644
--- a/core/modules/forum/tests/src/Unit/Breadcrumb/ForumBreadcrumbBuilderBaseTest.php
+++ b/core/modules/forum/tests/src/Unit/Breadcrumb/ForumBreadcrumbBuilderBaseTest.php
@@ -7,8 +7,10 @@
 
 namespace Drupal\Tests\forum\Unit\Breadcrumb;
 
+use Drupal\Core\Cache\Cache;
 use Drupal\Core\Link;
 use Drupal\Tests\UnitTestCase;
+use Symfony\Component\DependencyInjection\Container;
 
 /**
  * @coversDefaultClass \Drupal\forum\Breadcrumb\ForumBreadcrumbBuilderBase
@@ -17,6 +19,22 @@
 class ForumBreadcrumbBuilderBaseTest extends UnitTestCase {
 
   /**
+   * {@inheritdoc}
+   */
+  public function setUp() {
+    parent::setUp();
+
+    $cache_contexts_manager = $this->getMockBuilder('Drupal\Core\Cache\Context\CacheContextsManager')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $cache_contexts_manager->expects($this->any())
+      ->method('validate_tokens');
+    $container = new Container();
+    $container->set('cache_contexts_manager', $cache_contexts_manager);
+    \Drupal::setContainer($container);
+  }
+
+  /**
    * Tests ForumBreadcrumbBuilderBase::__construct().
    *
    * @covers ::__construct
@@ -78,6 +96,15 @@ public function testBuild() {
     $vocab_item->expects($this->any())
       ->method('label')
       ->will($this->returnValue('Fora_is_the_plural_of_forum'));
+    $vocab_item->expects($this->once())
+      ->method('getCacheTags')
+      ->willReturn([]);
+    $vocab_item->expects($this->once())
+      ->method('getCacheContexts')
+      ->willReturn([]);
+    $vocab_item->expects($this->once())
+      ->method('getCacheMaxAge')
+      ->willReturn(Cache::PERMANENT);
 
     $vocab_storage = $this->getMock('Drupal\Core\Entity\EntityStorageInterface');
     $vocab_storage->expects($this->any())
@@ -128,7 +155,7 @@ public function testBuild() {
     );
 
     // And finally, the test.
-    $this->assertEquals($expected, $breadcrumb_builder->build($route_match));
+    $this->assertEquals($expected, $breadcrumb_builder->build($route_match)->getLinks());
   }
 
 }
diff --git a/core/modules/forum/tests/src/Unit/Breadcrumb/ForumListingBreadcrumbBuilderTest.php b/core/modules/forum/tests/src/Unit/Breadcrumb/ForumListingBreadcrumbBuilderTest.php
index 95c670f..6331e86 100644
--- a/core/modules/forum/tests/src/Unit/Breadcrumb/ForumListingBreadcrumbBuilderTest.php
+++ b/core/modules/forum/tests/src/Unit/Breadcrumb/ForumListingBreadcrumbBuilderTest.php
@@ -7,9 +7,11 @@
 
 namespace Drupal\Tests\forum\Unit\Breadcrumb;
 
+use Drupal\Core\Cache\Cache;
 use Drupal\Core\Link;
 use Drupal\Tests\UnitTestCase;
 use Symfony\Cmf\Component\Routing\RouteObjectInterface;
+use Symfony\Component\DependencyInjection\Container;
 
 /**
  * @coversDefaultClass \Drupal\forum\Breadcrumb\ForumListingBreadcrumbBuilder
@@ -18,6 +20,22 @@
 class ForumListingBreadcrumbBuilderTest extends UnitTestCase {
 
   /**
+   * {@inheritdoc}
+   */
+  public function setUp() {
+    parent::setUp();
+
+    $cache_contexts_manager = $this->getMockBuilder('Drupal\Core\Cache\Context\CacheContextsManager')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $cache_contexts_manager->expects($this->any())
+      ->method('validate_tokens');
+    $container = new Container();
+    $container->set('cache_contexts_manager', $cache_contexts_manager);
+    \Drupal::setContainer($container);
+  }
+
+  /**
    * Tests ForumListingBreadcrumbBuilder::applies().
    *
    * @param bool $expected
@@ -114,6 +132,7 @@ public function testBuild() {
     $term1->expects($this->any())
       ->method('id')
       ->will($this->returnValue(1));
+    $this->addEmptyCacheableMetadata($term1);
 
     $term2 = $this->getMockBuilder('Drupal\taxonomy\Entity\Term')
       ->disableOriginalConstructor()
@@ -124,6 +143,7 @@ public function testBuild() {
     $term2->expects($this->any())
       ->method('id')
       ->will($this->returnValue(2));
+    $this->addEmptyCacheableMetadata($term2);
 
     $forum_manager = $this->getMock('Drupal\forum\ForumManagerInterface');
     $forum_manager->expects($this->at(0))
@@ -138,6 +158,7 @@ public function testBuild() {
     $vocab_item->expects($this->any())
       ->method('label')
       ->will($this->returnValue('Fora_is_the_plural_of_forum'));
+    $this->addEmptyCacheableMetadata($vocab_item);
     $vocab_storage = $this->getMock('Drupal\Core\Entity\EntityStorageInterface');
     $vocab_storage->expects($this->any())
       ->method('load')
@@ -183,6 +204,7 @@ public function testBuild() {
     $forum_listing->expects($this->any())
       ->method('label')
       ->will($this->returnValue('You_should_not_see_this'));
+    $this->addEmptyCacheableMetadata($forum_listing);
 
     // Our data set.
     $route_match = $this->getMock('Drupal\Core\Routing\RouteMatchInterface');
@@ -197,7 +219,7 @@ public function testBuild() {
       Link::createFromRoute('Fora_is_the_plural_of_forum', 'forum.index'),
       Link::createFromRoute('Something', 'forum.page', array('taxonomy_term' => 1)),
     );
-    $this->assertEquals($expected1, $breadcrumb_builder->build($route_match));
+    $this->assertEquals($expected1, $breadcrumb_builder->build($route_match)->getLinks());
 
     // Second test.
     $expected2 = array(
@@ -206,7 +228,24 @@ public function testBuild() {
       Link::createFromRoute('Something else', 'forum.page', array('taxonomy_term' => 2)),
       Link::createFromRoute('Something', 'forum.page', array('taxonomy_term' => 1)),
     );
-    $this->assertEquals($expected2, $breadcrumb_builder->build($route_match));
+    $this->assertEquals($expected2, $breadcrumb_builder->build($route_match)->getLinks());
+  }
+
+  /**
+   * Adds empty CacheableMetadata for objects.
+   *
+   * @param \PHPUnit_Framework_MockObject_MockObject $object
+   */
+  protected function addEmptyCacheableMetadata(&$object) {
+    $object->expects($this->any())
+      ->method('getCacheTags')
+      ->willReturn([]);
+    $object->expects($this->any())
+      ->method('getCacheContexts')
+      ->willReturn([]);
+    $object->expects($this->any())
+      ->method('getCacheMaxAge')
+      ->willReturn(Cache::PERMANENT);
   }
 
 }
diff --git a/core/modules/forum/tests/src/Unit/Breadcrumb/ForumNodeBreadcrumbBuilderTest.php b/core/modules/forum/tests/src/Unit/Breadcrumb/ForumNodeBreadcrumbBuilderTest.php
index ec5dec0..2646ba1 100644
--- a/core/modules/forum/tests/src/Unit/Breadcrumb/ForumNodeBreadcrumbBuilderTest.php
+++ b/core/modules/forum/tests/src/Unit/Breadcrumb/ForumNodeBreadcrumbBuilderTest.php
@@ -7,9 +7,10 @@
 
 namespace Drupal\Tests\forum\Unit\Breadcrumb;
 
+use Drupal\Core\Cache\Cache;
 use Drupal\Core\Link;
 use Drupal\Tests\UnitTestCase;
-use Symfony\Cmf\Component\Routing\RouteObjectInterface;
+use Symfony\Component\DependencyInjection\Container;
 
 /**
  * @coversDefaultClass \Drupal\forum\Breadcrumb\ForumNodeBreadcrumbBuilder
@@ -18,6 +19,22 @@
 class ForumNodeBreadcrumbBuilderTest extends UnitTestCase {
 
   /**
+   * {@inheritdoc}
+   */
+  public function setUp() {
+    parent::setUp();
+
+    $cache_contexts_manager = $this->getMockBuilder('Drupal\Core\Cache\Context\CacheContextsManager')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $cache_contexts_manager->expects($this->any())
+      ->method('validate_tokens');
+    $container = new Container();
+    $container->set('cache_contexts_manager', $cache_contexts_manager);
+    \Drupal::setContainer($container);
+  }
+
+  /**
    * Tests ForumNodeBreadcrumbBuilder::applies().
    *
    * @param bool $expected
@@ -121,6 +138,7 @@ public function testBuild() {
     $term1->expects($this->any())
       ->method('id')
       ->will($this->returnValue(1));
+    $this->addEmptyCacheableMetadata($term1);
 
     $term2 = $this->getMockBuilder('Drupal\Core\Entity\EntityInterface')
       ->disableOriginalConstructor()
@@ -131,6 +149,7 @@ public function testBuild() {
     $term2->expects($this->any())
       ->method('id')
       ->will($this->returnValue(2));
+    $this->addEmptyCacheableMetadata($term2);
 
     $forum_manager = $this->getMockBuilder('Drupal\forum\ForumManagerInterface')
       ->disableOriginalConstructor()
@@ -146,6 +165,7 @@ public function testBuild() {
     $vocab_item->expects($this->any())
       ->method('label')
       ->will($this->returnValue('Forums'));
+    $this->addEmptyCacheableMetadata($vocab_item);
     $vocab_storage = $this->getMock('Drupal\Core\Entity\EntityStorageInterface');
     $vocab_storage->expects($this->any())
       ->method('load')
@@ -203,7 +223,7 @@ public function testBuild() {
       Link::createFromRoute('Forums', 'forum.index'),
       Link::createFromRoute('Something', 'forum.page', array('taxonomy_term' => 1)),
     );
-    $this->assertEquals($expected1, $breadcrumb_builder->build($route_match));
+    $this->assertEquals($expected1, $breadcrumb_builder->build($route_match)->getLinks());
 
     // Second test.
     $expected2 = array(
@@ -212,7 +232,24 @@ public function testBuild() {
       Link::createFromRoute('Something else', 'forum.page', array('taxonomy_term' => 2)),
       Link::createFromRoute('Something', 'forum.page', array('taxonomy_term' => 1)),
     );
-    $this->assertEquals($expected2, $breadcrumb_builder->build($route_match));
+    $this->assertEquals($expected2, $breadcrumb_builder->build($route_match)->getLinks());
+  }
+
+  /**
+   * Adds empty CacheableMetadata for objects.
+   *
+   * @param \PHPUnit_Framework_MockObject_MockObject $object
+   */
+  protected function addEmptyCacheableMetadata(&$object) {
+    $object->expects($this->any())
+      ->method('getCacheTags')
+      ->willReturn([]);
+    $object->expects($this->any())
+      ->method('getCacheContexts')
+      ->willReturn([]);
+    $object->expects($this->any())
+      ->method('getCacheMaxAge')
+      ->willReturn(Cache::PERMANENT);
   }
 
 }
diff --git a/core/modules/menu_ui/menu_ui.module b/core/modules/menu_ui/menu_ui.module
index f26dade..07545e8 100644
--- a/core/modules/menu_ui/menu_ui.module
+++ b/core/modules/menu_ui/menu_ui.module
@@ -486,14 +486,14 @@ function menu_ui_preprocess_block(&$variables) {
 /**
  * Implements hook_system_breadcrumb_alter().
  */
-function menu_ui_system_breadcrumb_alter(array &$breadcrumb, RouteMatchInterface $route_match, array $context) {
+function menu_ui_system_breadcrumb_alter(&$breadcrumb, RouteMatchInterface $route_match, array $context) {
   // Custom breadcrumb behavior for editing menu links, we append a link to
   // the menu in which the link is found.
   if (($route_match->getRouteName() == 'menu_ui.link_edit') && $menu_link = $route_match->getParameter('menu_link_plugin')) {
     if (($menu_link instanceof MenuLinkInterface)) {
       // Add a link to the menu admin screen.
       $menu = Menu::load($menu_link->getMenuName());
-      $breadcrumb[] = Link::createFromRoute($menu->label(), 'entity.menu.edit_form', array('menu' => $menu->id()));
+      $breadcrumb->addLink(Link::createFromRoute($menu->label(), 'entity.menu.edit_form', array('menu' => $menu->id())));
     }
   }
 }
diff --git a/core/modules/node/src/Tests/NodeTranslationUITest.php b/core/modules/node/src/Tests/NodeTranslationUITest.php
index c392750..20d95fd 100644
--- a/core/modules/node/src/Tests/NodeTranslationUITest.php
+++ b/core/modules/node/src/Tests/NodeTranslationUITest.php
@@ -33,7 +33,8 @@ class NodeTranslationUITest extends ContentTranslationUITestBase {
     'route.menu_active_trails:main',
     'route.menu_active_trails:tools',
     'timezone',
-    'user.roles'
+    'user.roles',
+    'url.path',
   ];
 
   /**
diff --git a/core/modules/system/src/PathBasedBreadcrumbBuilder.php b/core/modules/system/src/PathBasedBreadcrumbBuilder.php
index c6e51af..2ee39b4 100644
--- a/core/modules/system/src/PathBasedBreadcrumbBuilder.php
+++ b/core/modules/system/src/PathBasedBreadcrumbBuilder.php
@@ -9,7 +9,9 @@
 
 use Drupal\Component\Utility\Unicode;
 use Drupal\Core\Access\AccessManagerInterface;
+use Drupal\Core\Breadcrumb\Breadcrumb;
 use Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface;
+use Drupal\Core\Cache\CacheableMetadata;
 use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Controller\TitleResolverInterface;
 use Drupal\Core\Link;
@@ -125,6 +127,7 @@ public function applies(RouteMatchInterface $route_match) {
    * {@inheritdoc}
    */
   public function build(RouteMatchInterface $route_match) {
+    $breadcrumb = new Breadcrumb();
     $links = array();
 
     // General path-based breadcrumbs. Use the actual request path, prior to
@@ -139,17 +142,21 @@ public function build(RouteMatchInterface $route_match) {
     // /user is just a redirect, so skip it.
     // @todo Find a better way to deal with /user.
     $exclude['/user'] = TRUE;
+    // Because this breadcrumb builder is entirely path-based, vary by the 'url.path'
+    // cache context.
+    $breadcrumb->setCacheContexts(['url.path']);
     while (count($path_elements) > 1) {
       array_pop($path_elements);
       // Copy the path elements for up-casting.
       $route_request = $this->getRequestForPath('/' . implode('/', $path_elements), $exclude);
       if ($route_request) {
         $route_match = RouteMatch::createFromRequest($route_request);
-        $access = $this->accessManager->check($route_match, $this->currentUser);
-        if ($access) {
+        $access = $this->accessManager->check($route_match, $this->currentUser, NULL, TRUE);
+        // The set of breadcrumb links depends on the access result, so merge
+        // the access result's cacheability metadata.
+        $breadcrumb = $breadcrumb->merge(CacheableMetadata::createFromObject($access));
+        if ($access->isAllowed()) {
           $title = $this->titleResolver->getTitle($route_request, $route_match->getRouteObject());
-        }
-        if ($access) {
           if (!isset($title)) {
             // Fallback to using the raw path component as the title if the
             // route is missing a _title or _title_callback attribute.
@@ -165,7 +172,8 @@ public function build(RouteMatchInterface $route_match) {
       // Add the Home link, except for the front page.
       $links[] = Link::createFromRoute($this->t('Home'), '<front>');
     }
-    return array_reverse($links);
+
+    return $breadcrumb->setLinks(array_reverse($links));
   }
 
   /**
diff --git a/core/modules/system/src/Plugin/Block/SystemBreadcrumbBlock.php b/core/modules/system/src/Plugin/Block/SystemBreadcrumbBlock.php
index c7629f0..40da616 100644
--- a/core/modules/system/src/Plugin/Block/SystemBreadcrumbBlock.php
+++ b/core/modules/system/src/Plugin/Block/SystemBreadcrumbBlock.php
@@ -77,20 +77,13 @@ public function build() {
     $breadcrumb = $this->breadcrumbManager->build($this->routeMatch);
     if (!empty($breadcrumb)) {
       // $breadcrumb is expected to be an array of rendered breadcrumb links.
-      return array(
+      $build = [
         '#theme' => 'breadcrumb',
-        '#links' => $breadcrumb,
-      );
+        '#links' => $breadcrumb->getLinks(),
+      ];
+      $breadcrumb->applyTo($build);
+      return $build;
     }
   }
 
-  /**
-   * {@inheritdoc}
-   *
-   * @todo Make cacheable in https://www.drupal.org/node/2483183
-   */
-  public function getCacheMaxAge() {
-    return 0;
-  }
-
 }
diff --git a/core/modules/system/tests/src/Unit/Breadcrumbs/PathBasedBreadcrumbBuilderTest.php b/core/modules/system/tests/src/Unit/Breadcrumbs/PathBasedBreadcrumbBuilderTest.php
index 0a00029..052f9f6 100644
--- a/core/modules/system/tests/src/Unit/Breadcrumbs/PathBasedBreadcrumbBuilderTest.php
+++ b/core/modules/system/tests/src/Unit/Breadcrumbs/PathBasedBreadcrumbBuilderTest.php
@@ -8,11 +8,12 @@
 namespace Drupal\Tests\system\Unit\Breadcrumbs;
 
 use Drupal\Core\Link;
-use Drupal\Core\Access\AccessResult;
+use Drupal\Core\Access\AccessResultAllowed;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\StringTranslation\TranslationInterface;
 use Drupal\Core\Url;
 use Drupal\Core\Utility\LinkGeneratorInterface;
+use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\system\PathBasedBreadcrumbBuilder;
 use Drupal\Tests\UnitTestCase;
 use Symfony\Cmf\Component\Routing\RouteObjectInterface;
@@ -130,7 +131,7 @@ public function testBuildOnFrontpage() {
       ->will($this->returnValue('/'));
 
     $links = $this->builder->build($this->getMock('Drupal\Core\Routing\RouteMatchInterface'));
-    $this->assertEquals(array(), $links);
+    $this->assertEquals([], $links->getLinks());
   }
 
   /**
@@ -144,7 +145,7 @@ public function testBuildWithOnePathElement() {
       ->will($this->returnValue('/example'));
 
     $links = $this->builder->build($this->getMock('Drupal\Core\Routing\RouteMatchInterface'));
-    $this->assertEquals(array(0 => new Link('Home', new Url('<front>'))), $links);
+    $this->assertEquals([0 => new Link('Home', new Url('<front>'))], $links->getLinks());
   }
 
   /**
@@ -176,7 +177,7 @@ public function testBuildWithTwoPathElements() {
     $this->setupAccessManagerToAllow();
 
     $links = $this->builder->build($this->getMock('Drupal\Core\Routing\RouteMatchInterface'));
-    $this->assertEquals(array(0 => new Link('Home', new Url('<front>')), 1 => new Link('Example', new Url('example'))), $links);
+    $this->assertEquals([0 => new Link('Home', new Url('<front>')), 1 => new Link('Example', new Url('example'))], $links->getLinks());
   }
 
   /**
@@ -216,11 +217,11 @@ public function testBuildWithThreePathElements() {
     $this->setupAccessManagerToAllow();
 
     $links = $this->builder->build($this->getMock('Drupal\Core\Routing\RouteMatchInterface'));
-    $this->assertEquals(array(
+    $this->assertEquals([
       new Link('Home', new Url('<front>')),
       new Link('Example', new Url('example')),
       new Link('Bar', new Url('example_bar')),
-    ), $links);
+    ], $links->getLinks());
   }
 
   /**
@@ -244,7 +245,7 @@ public function testBuildWithException($exception_class, $exception_argument) {
     $links = $this->builder->build($this->getMock('Drupal\Core\Routing\RouteMatchInterface'));
 
     // No path matched, though at least the frontpage is displayed.
-    $this->assertEquals(array(0 => new Link('Home', new Url('<front>'))), $links);
+    $this->assertEquals([0 => new Link('Home', new Url('<front>'))], $links->getLinks());
   }
 
   /**
@@ -285,7 +286,7 @@ public function testBuildWithNonProcessedPath() {
     $links = $this->builder->build($this->getMock('Drupal\Core\Routing\RouteMatchInterface'));
 
     // No path matched, though at least the frontpage is displayed.
-    $this->assertEquals(array(0 => new Link('Home', new Url('<front>'))), $links);
+    $this->assertEquals([0 => new Link('Home', new Url('<front>'))], $links->getLinks());
   }
 
   /**
@@ -330,7 +331,7 @@ public function testBuildWithUserPath() {
       ->will($this->returnValue('Admin'));
 
     $links = $this->builder->build($this->getMock('Drupal\Core\Routing\RouteMatchInterface'));
-    $this->assertEquals(array(0 => new Link('Home', new Url('<front>')), 1 => new Link('Admin', new Url('user_page'))), $links);
+    $this->assertEquals([0 => new Link('Home', new Url('<front>')), 1 => new Link('Admin', new Url('user_page'))], $links->getLinks());
   }
 
   /**
@@ -339,7 +340,7 @@ public function testBuildWithUserPath() {
   public function setupAccessManagerToAllow() {
     $this->accessManager->expects($this->any())
       ->method('check')
-      ->willReturn(TRUE);
+      ->willReturn(new AccessResultAllowed());
   }
 
   protected function setupStubPathProcessor() {
diff --git a/core/modules/taxonomy/src/TermBreadcrumbBuilder.php b/core/modules/taxonomy/src/TermBreadcrumbBuilder.php
index c2e47a1..ef1ec30 100644
--- a/core/modules/taxonomy/src/TermBreadcrumbBuilder.php
+++ b/core/modules/taxonomy/src/TermBreadcrumbBuilder.php
@@ -8,6 +8,8 @@
 namespace Drupal\taxonomy;
 
 use Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface;
+use Drupal\Core\Breadcrumb\Breadcrumb;
+use Drupal\Core\Cache\CacheableMetadata;
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Link;
 use Drupal\Core\Routing\RouteMatchInterface;
@@ -29,7 +31,7 @@ class TermBreadcrumbBuilder implements BreadcrumbBuilderInterface {
   /**
    * The taxonomy storage.
    *
-   * @var \Drupal\Core\Entity\EntityStorageInterface
+   * @var \Drupal\Core\Entity\TermStorageInterface
    */
   protected $termStorage;
 
@@ -56,18 +58,28 @@ public function applies(RouteMatchInterface $route_match) {
    * {@inheritdoc}
    */
   public function build(RouteMatchInterface $route_match) {
+    $breadcrumb = new Breadcrumb();
+    $breadcrumb->addLink(Link::createFromRoute($this->t('Home'), '<front>'));
     $term = $route_match->getParameter('taxonomy_term');
+    // Breadcrumb needs to have terms cacheable metadata as dependency even
+    // though its not shown on the breadcrumb because e.g. its parent might have
+    // changed.
+    $breadcrumb->addCacheableDependency($term);
     // @todo This overrides any other possible breadcrumb and is a pure
     //   hard-coded presumption. Make this behavior configurable per
     //   vocabulary or term.
-    $breadcrumb = array();
-    while ($parents = $this->termStorage->loadParents($term->id())) {
-      $term = array_shift($parents);
+    $parents = $this->termStorage->loadAllParents($term->id());
+    // Remove current term being accessed.
+    array_shift($parents);
+    foreach (array_reverse($parents) as $term) {
       $term = $this->entityManager->getTranslationFromContext($term);
-      $breadcrumb[] = Link::createFromRoute($term->getName(), 'entity.taxonomy_term.canonical', array('taxonomy_term' => $term->id()));
+      $breadcrumb->addCacheableDependency($term);
+      $breadcrumb->addLink(Link::createFromRoute($term->getName(), 'entity.taxonomy_term.canonical', array('taxonomy_term' => $term->id())));
     }
-    $breadcrumb[] = Link::createFromRoute($this->t('Home'), '<front>');
-    $breadcrumb = array_reverse($breadcrumb);
+
+    // This breadcrumb builder is based on a route parameter, and hence it
+    // depends on the 'route' cache context.
+    $breadcrumb->setCacheContexts(['route']);
 
     return $breadcrumb;
   }
diff --git a/core/tests/Drupal/Tests/Core/Breadcrumb/BreadcrumbManagerTest.php b/core/tests/Drupal/Tests/Core/Breadcrumb/BreadcrumbManagerTest.php
index a2cbbf0..4a12f93 100644
--- a/core/tests/Drupal/Tests/Core/Breadcrumb/BreadcrumbManagerTest.php
+++ b/core/tests/Drupal/Tests/Core/Breadcrumb/BreadcrumbManagerTest.php
@@ -7,8 +7,10 @@
 
 namespace Drupal\Tests\Core\Breadcrumb;
 
+use Drupal\Core\Breadcrumb\Breadcrumb;
 use Drupal\Core\Breadcrumb\BreadcrumbManager;
 use Drupal\Tests\UnitTestCase;
+use PHPUnit_Framework_Assert as Assert;
 
 /**
  * @coversDefaultClass \Drupal\Core\Breadcrumb\BreadcrumbManager
@@ -17,6 +19,13 @@
 class BreadcrumbManagerTest extends UnitTestCase {
 
   /**
+   * The breadcrumb object.
+   *
+   * @var \Drupal\Core\Breadcrumb\Breadcrumb
+   */
+  protected $breadcrumb;
+
+  /**
    * The tested breadcrumb manager.
    *
    * @var \Drupal\Core\Breadcrumb\BreadcrumbManager
@@ -36,6 +45,7 @@ class BreadcrumbManagerTest extends UnitTestCase {
   protected function setUp() {
     $this->moduleHandler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface');
     $this->breadcrumbManager = new BreadcrumbManager($this->moduleHandler);
+    $this->breadcrumb = new Breadcrumb();
   }
 
   /**
@@ -43,7 +53,7 @@ protected function setUp() {
    */
   public function testBuildWithoutBuilder() {
     $result = $this->breadcrumbManager->build($this->getMock('Drupal\Core\Routing\RouteMatchInterface'));
-    $this->assertEquals(array(), $result);
+    $this->assertEquals(array(), $result->getLinks());
   }
 
   /**
@@ -51,7 +61,8 @@ public function testBuildWithoutBuilder() {
    */
   public function testBuildWithSingleBuilder() {
     $builder = $this->getMock('Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface');
-    $breadcrumb = array('<a href="/example">Test</a>');
+    $links = array('<a href="/example">Test</a>');
+    $this->breadcrumb->setLinks($links);
 
     $builder->expects($this->once())
       ->method('applies')
@@ -59,17 +70,24 @@ public function testBuildWithSingleBuilder() {
 
     $builder->expects($this->once())
       ->method('build')
-      ->will($this->returnValue($breadcrumb));
+      ->willReturn($this->breadcrumb);
 
     $route_match = $this->getMock('Drupal\Core\Routing\RouteMatchInterface');
     $this->moduleHandler->expects($this->once())
       ->method('alter')
-      ->with('system_breadcrumb', $breadcrumb, $route_match, array('builder' => $builder));
+      ->willReturnCallback(function($type, $data, $context1, $context2) use ($route_match, $links, $builder) {
+        Assert::assertEquals($type, 'system_breadcrumb', 'SingleTest: Module handler expected alter call to system_breadcrumb');
+        $extracted_links = $data->getLinks();
+        Assert::assertEquals($extracted_links, $links, 'SingleTest: Module handler was passed the correct link');
+        Assert::assertEquals($context1, $route_match, 'SingleTest: Module handler was passed route_match.');
+        Assert::assertEquals($context2, array('builder' => $builder), 'SingleTest: Module handler received the builder context');
+        }
+      );
 
     $this->breadcrumbManager->addBuilder($builder, 0);
 
     $result = $this->breadcrumbManager->build($route_match);
-    $this->assertEquals($breadcrumb, $result);
+    $this->assertEquals($links, $result->getLinks());
   }
 
   /**
@@ -83,25 +101,33 @@ public function testBuildWithMultipleApplyingBuilders() {
       ->method('build');
 
     $builder2 = $this->getMock('Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface');
-    $breadcrumb2 = array('<a href="/example2">Test2</a>');
+    $links2 = array('<a href="/example2">Test2</a>');
+    $this->breadcrumb->setLinks($links2);
     $builder2->expects($this->once())
       ->method('applies')
       ->will($this->returnValue(TRUE));
     $builder2->expects($this->once())
       ->method('build')
-      ->will($this->returnValue($breadcrumb2));
+      ->willReturn($this->breadcrumb);
 
     $route_match = $this->getMock('Drupal\Core\Routing\RouteMatchInterface');
 
     $this->moduleHandler->expects($this->once())
       ->method('alter')
-      ->with('system_breadcrumb', $breadcrumb2, $route_match, array('builder' => $builder2));
+         ->willReturnCallback(function($type, $data, $context1, $context2) use ($links2, $route_match, $builder2) {
+        Assert::assertEquals($type, 'system_breadcrumb', 'MultipleApplying: Module handler expected alter call to system_breadcrumb');
+        $extracted_links = $data->getLinks();
+        Assert::assertEquals($extracted_links, $links2, 'MultipleApplying: Module handler was passed the correct link');
+        Assert::assertEquals($context1, $route_match, 'MultipleApplying: Module handler was passed route_match.');
+        Assert::assertEquals($context2, array('builder' => $builder2), 'MultipleApplying: Module handler received the builder context');
+        }
+      );
 
     $this->breadcrumbManager->addBuilder($builder1, 0);
     $this->breadcrumbManager->addBuilder($builder2, 10);
 
     $result = $this->breadcrumbManager->build($route_match);
-    $this->assertEquals($breadcrumb2, $result);
+    $this->assertEquals($links2, $result->getLinks());
   }
 
   /**
@@ -116,25 +142,33 @@ public function testBuildWithOneNotApplyingBuilders() {
       ->method('build');
 
     $builder2 = $this->getMock('Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface');
-    $breadcrumb2 = array('<a href="/example2">Test2</a>');
+    $links2 = ['<a href="/example2">Test2</a>'];
+    $this->breadcrumb->setLinks($links2);
     $builder2->expects($this->once())
       ->method('applies')
       ->will($this->returnValue(TRUE));
     $builder2->expects($this->once())
       ->method('build')
-      ->will($this->returnValue($breadcrumb2));
+      ->willReturn($this->breadcrumb);
 
     $route_match = $this->getMock('Drupal\Core\Routing\RouteMatchInterface');
 
     $this->moduleHandler->expects($this->once())
       ->method('alter')
-      ->with('system_breadcrumb', $breadcrumb2, $route_match, array('builder' => $builder2));
+      ->willReturnCallback(function($type, $data, $context1, $context2) use ($links2, $route_match, $builder2) {
+        Assert::assertEquals($type, 'system_breadcrumb', 'NotApplying: Module handler expected alter call to system_breadcrumb');
+        $extracted_links = $data->getLinks();
+        Assert::assertEquals($extracted_links, $links2, 'NotApplying: Module handler was passed the correct link');
+        Assert::assertEquals($context1, $route_match, 'NotApplying: Module handler was passed route_match.');
+        Assert::assertEquals($context2, array('builder' => $builder2), 'NotApplying: Module handler received the builder context');
+        }
+      );
 
     $this->breadcrumbManager->addBuilder($builder1, 10);
     $this->breadcrumbManager->addBuilder($builder2, 0);
 
     $result = $this->breadcrumbManager->build($route_match);
-    $this->assertEquals($breadcrumb2, $result);
+    $this->assertEquals($links2, $result->getLinks());
   }
 
   /**
