diff --git a/core/lib/Drupal/Core/Routing/CompiledRoute.php b/core/lib/Drupal/Core/Routing/CompiledRoute.php
index 7354e1225a460621c2f2bc661e8fb5f19b702506..05eede7e0e483ae183dfe44b6a60f84f3961d6d1 100644
--- a/core/lib/Drupal/Core/Routing/CompiledRoute.php
+++ b/core/lib/Drupal/Core/Routing/CompiledRoute.php
@@ -7,7 +7,6 @@
 
 namespace Drupal\Core\Routing;
 
-use Symfony\Component\Routing\Route;
 use Symfony\Component\Routing\CompiledRoute as SymfonyCompiledRoute;
 
 /**
@@ -36,13 +35,6 @@ class CompiledRoute extends SymfonyCompiledRoute {
    */
   protected $numParts;
 
-  /**
-   * The Route object of which this object is the compiled version.
-   *
-   * @var \Symfony\Component\Routing\Route
-   */
-  protected $route;
-
   /**
    * Constructs a new compiled route object.
    *
@@ -51,11 +43,9 @@ class CompiledRoute extends SymfonyCompiledRoute {
    * problem. The parent Symfony class does the same, as well, making it
    * difficult to override differently.
    *
-   * @param \Symfony\Component\Routing\Route $route
-   *   A original Route instance.
    * @param int $fit
    *   The fitness of the route.
-   * @param string $fit
+   * @param string $pattern_outline
    *   The pattern outline for this route.
    * @param int $num_parts
    *   The number of parts in the path.
@@ -76,10 +66,9 @@ class CompiledRoute extends SymfonyCompiledRoute {
    * @param array $variables
    *   An array of variables (variables defined in the path and in the host patterns)
    */
-  public function __construct(Route $route, $fit, $pattern_outline, $num_parts, $staticPrefix, $regex, array $tokens, array $pathVariables, $hostRegex = null, array $hostTokens = array(), array $hostVariables = array(), array $variables = array()) {
+  public function __construct($fit, $pattern_outline, $num_parts, $staticPrefix, $regex, array $tokens, array $pathVariables, $hostRegex = null, array $hostTokens = array(), array $hostVariables = array(), array $variables = array()) {
     parent::__construct($staticPrefix, $regex, $tokens, $pathVariables, $hostRegex, $hostTokens, $hostVariables, $variables);
 
-    $this->route = $route;
     $this->fit = $fit;
     $this->patternOutline = $pattern_outline;
     $this->numParts = $num_parts;
@@ -123,26 +112,6 @@ public function getPatternOutline() {
     return $this->patternOutline;
   }
 
-  /**
-   * Returns the Route instance.
-   *
-   * @return Route
-   *   A Route instance.
-   */
-  public function getRoute() {
-    return $this->route;
-  }
-
-  /**
-   * Returns the path.
-   *
-   * @return string
-   *   The path.
-   */
-  public function getPath() {
-    return $this->route->getPath();
-  }
-
   /**
    * Returns the options.
    *
@@ -177,6 +146,8 @@ public function getRequirements() {
    * {@inheritdoc}
    */
   public function serialize() {
+    // Calling the parent method is safer than trying to optimize out the extra
+    // function calls.
     $data = unserialize(parent::serialize());
     $data['fit'] = $this->fit;
     $data['patternOutline'] = $this->patternOutline;
@@ -188,8 +159,7 @@ public function serialize() {
   /**
    * {@inheritdoc}
    */
-  public function unserialize($serialized)
-  {
+  public function unserialize($serialized) {
     parent::unserialize($serialized);
     $data = unserialize($serialized);
 
diff --git a/core/lib/Drupal/Core/Routing/MatcherDumper.php b/core/lib/Drupal/Core/Routing/MatcherDumper.php
index 0b409467bcbb171b61ae1a86fba6c6ef7eb9ba50..43e3219c2a579d72b088d7aace07c3031f3ea3c9 100644
--- a/core/lib/Drupal/Core/Routing/MatcherDumper.php
+++ b/core/lib/Drupal/Core/Routing/MatcherDumper.php
@@ -114,6 +114,7 @@ public function dump(array $options = array()) {
         foreach ($routes as $name => $route) {
           /** @var \Symfony\Component\Routing\Route $route */
           $route->setOption('compiler_class', '\Drupal\Core\Routing\RouteCompiler');
+          /** @var \Drupal\Core\Routing\CompiledRoute $compiled */
           $compiled = $route->compile();
           // The fit value is a binary number which has 1 at every fixed path
           // position and 0 where there is a wildcard. We keep track of all such
@@ -124,7 +125,7 @@ public function dump(array $options = array()) {
           $values = array(
             'name' => $name,
             'fit' => $compiled->getFit(),
-            'path' => $compiled->getPath(),
+            'path' => $route->getPath(),
             'pattern_outline' => $compiled->getPatternOutline(),
             'number_parts' => $compiled->getNumParts(),
             'route' => serialize($route),
diff --git a/core/lib/Drupal/Core/Routing/PreloadableRouteProviderInterface.php b/core/lib/Drupal/Core/Routing/PreloadableRouteProviderInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..fc490df2c06c4c5927c0629dfdd638b60e609276
--- /dev/null
+++ b/core/lib/Drupal/Core/Routing/PreloadableRouteProviderInterface.php
@@ -0,0 +1,27 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Routing\PreloadableRouteProviderInterface.
+ */
+
+namespace Drupal\Core\Routing;
+
+/**
+ * Extends the router provider interface to pre-load routes.
+ */
+interface PreloadableRouteProviderInterface extends RouteProviderInterface {
+
+  /**
+   * Pre-load routes by their names using the provided list of names.
+   *
+   * This method exists in order to allow performance optimizations. It allows
+   * pre-loading serialized routes that may latter be retrieved using
+   * ::getRoutesByName()
+   *
+   * @param string[] $names
+   *   Array of route names to load.
+   */
+  public function preLoadRoutes($names);
+
+}
diff --git a/core/lib/Drupal/Core/Routing/RouteCompiler.php b/core/lib/Drupal/Core/Routing/RouteCompiler.php
index 9e6de2c4d9fa99e246f01ea03c8561ae8c9ecb34..5c129cc34bd4a3026d5ec7bfcc3c9a6391f46163 100644
--- a/core/lib/Drupal/Core/Routing/RouteCompiler.php
+++ b/core/lib/Drupal/Core/Routing/RouteCompiler.php
@@ -46,7 +46,6 @@ public static function compile(Route $route) {
     $num_parts = count(explode('/', trim($pattern_outline, '/')));
 
     return new CompiledRoute(
-      $route,
       $fit,
       $pattern_outline,
       $num_parts,
diff --git a/core/lib/Drupal/Core/Routing/RoutePreloader.php b/core/lib/Drupal/Core/Routing/RoutePreloader.php
index 1f223bfd48608753b32dbc716e699b74322008cc..23a09aa33f21ce6ab71070ac9eb4722404f62a71 100644
--- a/core/lib/Drupal/Core/Routing/RoutePreloader.php
+++ b/core/lib/Drupal/Core/Routing/RoutePreloader.php
@@ -25,7 +25,7 @@ class RoutePreloader implements EventSubscriberInterface {
   /**
    * The route provider.
    *
-   * @var \Drupal\Core\Routing\RouteProviderInterface
+   * @var \Drupal\Core\Routing\RouteProviderInterface|\Drupal\Core\Routing\PreloadableRouteProviderInterface
    */
   protected $routeProvider;
 
@@ -63,18 +63,12 @@ public function __construct(RouteProviderInterface $route_provider, StateInterfa
    *   The event to process.
    */
   public function onRequest(KernelEvent $event) {
-    // Just preload on normal HTML pages, as they will display menu links.
-    if ($event->getRequest()->getRequestFormat() == 'html') {
-      $this->loadNonAdminRoutes();
-    }
-  }
-
-  /**
-   * Load all the non-admin routes at once.
-   */
-  protected function loadNonAdminRoutes() {
-    if ($routes = $this->state->get('routing.non_admin_routes', array())) {
-      $this->routeProvider->getRoutesByNames($routes);
+    // Only preload on normal HTML pages, as they will display menu links.
+    if ($this->routeProvider instanceof PreloadableRouteProviderInterface && $event->getRequest()->getRequestFormat() == 'html') {
+      if ($routes = $this->state->get('routing.non_admin_routes', [])) {
+        // Preload all the non-admin routes at once.
+        $this->routeProvider->preLoadRoutes($routes);
+      }
     }
   }
 
diff --git a/core/lib/Drupal/Core/Routing/RouteProvider.php b/core/lib/Drupal/Core/Routing/RouteProvider.php
index 4d389f1e9839f01c33908c2e3bf25eebb37c2d9a..8f98802cbb7e288eb6339ef25346dea04c507438 100644
--- a/core/lib/Drupal/Core/Routing/RouteProvider.php
+++ b/core/lib/Drupal/Core/Routing/RouteProvider.php
@@ -22,7 +22,7 @@
 /**
  * A Route Provider front-end for all Drupal-stored routes.
  */
-class RouteProvider implements RouteProviderInterface, PagedRouteProviderInterface, EventSubscriberInterface {
+class RouteProvider implements PreloadableRouteProviderInterface, PagedRouteProviderInterface, EventSubscriberInterface {
 
   /**
    * The database connection from which to read route information.
@@ -48,10 +48,17 @@ class RouteProvider implements RouteProviderInterface, PagedRouteProviderInterfa
   /**
    * A cache of already-loaded routes, keyed by route name.
    *
-   * @var array
+   * @var \Symfony\Component\Routing\Route[]
    */
   protected $routes = array();
 
+  /**
+   * A cache of already-loaded serialized routes, keyed by route name.
+   *
+   * @var string[]
+   */
+  protected $serializedRoutes = [];
+
   /**
    * The current path.
    *
@@ -131,34 +138,32 @@ public function getRouteByName($name) {
   }
 
   /**
-   * Find many routes by their names using the provided list of names.
-   *
-   * Note that this method may not throw an exception if some of the routes
-   * are not found. It will just return the list of those routes it found.
-   *
-   * This method exists in order to allow performance optimizations. The
-   * simple implementation could be to just repeatedly call
-   * $this->getRouteByName().
-   *
-   * @param array $names
-   *   The list of names to retrieve.
-   *
-   * @return \Symfony\Component\Routing\Route[]
-   *   Iterable thing with the keys the names of the $names argument.
+   * {@inheritdoc}
    */
-  public function getRoutesByNames($names) {
-
+  public function preLoadRoutes($names) {
     if (empty($names)) {
       throw new \InvalidArgumentException('You must specify the route names to load');
     }
 
-    $routes_to_load = array_diff($names, array_keys($this->routes));
+    $routes_to_load = array_diff($names, array_keys($this->routes), array_keys($this->serializedRoutes));
     if ($routes_to_load) {
       $result = $this->connection->query('SELECT name, route FROM {' . $this->connection->escapeTable($this->tableName) . '} WHERE name IN ( :names[] )', array(':names[]' => $routes_to_load));
       $routes = $result->fetchAllKeyed();
+      $this->serializedRoutes += $routes;
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getRoutesByNames($names) {
+    $this->preLoadRoutes($names);
 
-      foreach ($routes as $name => $route) {
-        $this->routes[$name] = unserialize($route);
+    foreach ($names as $name) {
+      // The specified route name might not exist or might be serialized.
+      if (!isset($this->routes[$name]) && isset($this->serializedRoutes[$name])) {
+        $this->routes[$name] = unserialize($this->serializedRoutes[$name]);
+        unset($this->serializedRoutes[$name]);
       }
     }
 
@@ -291,6 +296,7 @@ public function getAllRoutes() {
    */
   public function reset() {
     $this->routes  = array();
+    $this->serializedRoutes = array();
   }
 
   /**
diff --git a/core/modules/system/src/Tests/Routing/MockRouteProvider.php b/core/modules/system/src/Tests/Routing/MockRouteProvider.php
index dce1b27ffc5def2c9bd12c4e7f68b81e0cd97177..eba563fa12f036537428a03d771ac861948d1d6f 100644
--- a/core/modules/system/src/Tests/Routing/MockRouteProvider.php
+++ b/core/modules/system/src/Tests/Routing/MockRouteProvider.php
@@ -56,6 +56,13 @@ public function getRouteByName($name) {
     return reset($routes);
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function preLoadRoutes($names) {
+    // Nothing to do.
+  }
+
   /**
    * Implements \Symfony\Cmf\Component\Routing\RouteProviderInterface::getRoutesByName().
    */
diff --git a/core/tests/Drupal/Tests/Core/Routing/RouteCompilerTest.php b/core/tests/Drupal/Tests/Core/Routing/RouteCompilerTest.php
index 4d1977c499562b1bbe8bf9ccfbc1c85ac6453030..a64cd696462e740964c93f31149c7a1f30d8f322 100644
--- a/core/tests/Drupal/Tests/Core/Routing/RouteCompilerTest.php
+++ b/core/tests/Drupal/Tests/Core/Routing/RouteCompilerTest.php
@@ -62,7 +62,6 @@ public function testCompilation() {
     $route->setOption('compiler_class', 'Drupal\Core\Routing\RouteCompiler');
     $compiled = $route->compile();
 
-    $this->assertEquals($route, $compiled->getRoute(), 'Compiled route has the incorrect route object.');
     $this->assertEquals($compiled->getFit(), 5 /* That's 101 binary*/, 'The fit was incorrect.');
     $this->assertEquals($compiled->getPatternOutline(), '/test/%/more', 'The pattern outline was not correct.');
   }
@@ -79,7 +78,6 @@ public function testCompilationDefaultValue() {
     $route->setOption('compiler_class', 'Drupal\Core\Routing\RouteCompiler');
     $compiled = $route->compile();
 
-    $this->assertEquals($route, $compiled->getRoute(), 'Compiled route has an incorrect route object.');
     $this->assertEquals($compiled->getFit(), 5 /* That's 101 binary*/, 'The fit was not correct.');
     $this->assertEquals($compiled->getPatternOutline(), '/test/%/more', 'The pattern outline was not correct.');
   }
diff --git a/core/tests/Drupal/Tests/Core/Routing/RoutePreloaderTest.php b/core/tests/Drupal/Tests/Core/Routing/RoutePreloaderTest.php
index 5692e6a1df71e57d1f8671ce1ebd7122bcfbbebf..189aa92fb927e246b636b117963474472d0626a7 100644
--- a/core/tests/Drupal/Tests/Core/Routing/RoutePreloaderTest.php
+++ b/core/tests/Drupal/Tests/Core/Routing/RoutePreloaderTest.php
@@ -45,7 +45,7 @@ class RoutePreloaderTest extends UnitTestCase {
    * {@inheritdoc}
    */
   protected function setUp() {
-    $this->routeProvider = $this->getMock('Drupal\Core\Routing\RouteProviderInterface');
+    $this->routeProvider = $this->getMock('Drupal\Core\Routing\PreloadableRouteProviderInterface');
     $this->state = $this->getMock('\Drupal\Core\State\StateInterface');
     $this->preloader = new RoutePreloader($this->routeProvider, $this->state);
   }
@@ -153,8 +153,8 @@ public function testOnRequestOnHtml() {
       ->will($this->returnValue($request));
 
     $this->routeProvider->expects($this->once())
-      ->method('getRoutesByNames')
-      ->with(array('test2'));
+      ->method('preLoadRoutes')
+      ->with(['test2']);
     $this->state->expects($this->once())
       ->method('get')
       ->with('routing.non_admin_routes')