diff --git a/core/lib/Drupal/Core/EventSubscriber/ModuleRouteSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/ModuleRouteSubscriber.php
index 49f1a12..65caac6 100644
--- a/core/lib/Drupal/Core/EventSubscriber/ModuleRouteSubscriber.php
+++ b/core/lib/Drupal/Core/EventSubscriber/ModuleRouteSubscriber.php
@@ -36,7 +36,7 @@ public function __construct(ModuleHandlerInterface $module_handler) {
   /**
    * {@inheritdoc}
    */
-  protected function alterRoutes(RouteCollection $collection, $module) {
+  protected function alterRoutes(RouteCollection $collection) {
     foreach ($collection as $name => $route) {
       if ($route->hasRequirement('_module_dependencies')) {
         $modules = $route->getRequirement('_module_dependencies');
diff --git a/core/lib/Drupal/Core/EventSubscriber/SpecialAttributesRouteSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/SpecialAttributesRouteSubscriber.php
index c9f3e7d..8556561 100644
--- a/core/lib/Drupal/Core/EventSubscriber/SpecialAttributesRouteSubscriber.php
+++ b/core/lib/Drupal/Core/EventSubscriber/SpecialAttributesRouteSubscriber.php
@@ -21,7 +21,7 @@ class SpecialAttributesRouteSubscriber extends RouteSubscriberBase {
   /**
    * {@inheritdoc}
    */
-  protected function alterRoutes(RouteCollection $collection, $module) {
+  protected function alterRoutes(RouteCollection $collection) {
     $special_variables = array(
       'system_path',
       '_maintenance',
@@ -57,7 +57,7 @@ protected function alterRoutes(RouteCollection $collection, $module) {
    */
   public function onAlterRoutes(RouteBuildEvent $event) {
     $collection = $event->getRouteCollection();
-    return $this->alterRoutes($collection, $event->getProvider());
+    return $this->alterRoutes($collection);
   }
 
 }
diff --git a/core/lib/Drupal/Core/Routing/MatcherDumper.php b/core/lib/Drupal/Core/Routing/MatcherDumper.php
index b5e1338..33b4ce8 100644
--- a/core/lib/Drupal/Core/Routing/MatcherDumper.php
+++ b/core/lib/Drupal/Core/Routing/MatcherDumper.php
@@ -87,15 +87,10 @@ public function addRoutes(RouteCollection $routes) {
    *   An array of options.
    */
   public function dump(array $options = array()) {
-    $options += array(
-      'provider' => '',
-    );
-
     // If there are no new routes, just delete any previously existing of this
     // provider.
     if (empty($this->routes) || !count($this->routes)) {
       $this->connection->delete($this->tableName)
-        ->condition('provider', $options['provider'])
         ->execute();
     }
     // Convert all of the routes into database records.
@@ -123,7 +118,7 @@ public function dump(array $options = array()) {
         $names[] = $name;
         $values = array(
           'name' => $name,
-          'provider' => $options['provider'],
+          'provider' => isset($options['provider']) ? $options['provider'] : 'provider',
           'fit' => $compiled->getFit(),
           'path' => $compiled->getPath(),
           'pattern_outline' => $compiled->getPatternOutline(),
@@ -143,7 +138,6 @@ public function dump(array $options = array()) {
         // old records of this provider (which may no longer exist).
         $delete = $this->connection->delete($this->tableName);
         $or = $delete->orConditionGroup()
-          ->condition('provider', $options['provider'])
           ->condition('name', $names);
         $delete->condition($or);
         $delete->execute();
diff --git a/core/lib/Drupal/Core/Routing/RouteBuildEvent.php b/core/lib/Drupal/Core/Routing/RouteBuildEvent.php
index 502318d..c3f36ee 100644
--- a/core/lib/Drupal/Core/Routing/RouteBuildEvent.php
+++ b/core/lib/Drupal/Core/Routing/RouteBuildEvent.php
@@ -23,18 +23,13 @@ class RouteBuildEvent extends Event {
   protected $routeCollection;
 
   /**
-   * The provider of this route collection.
-   *
-   * @var string
-   */
-  protected $provider;
-
-  /**
    * Constructs a RouteBuildEvent object.
+   *
+   * @param \Symfony\Component\Routing\RouteCollection $route_collection
+   *   The route collection.
    */
-  public function __construct(RouteCollection $route_collection, $provider) {
+  public function __construct(RouteCollection $route_collection) {
     $this->routeCollection = $route_collection;
-    $this->provider = $provider;
   }
 
   /**
@@ -44,11 +39,4 @@ public function getRouteCollection() {
     return $this->routeCollection;
   }
 
-  /**
-   * Gets the provider for this route collection.
-   */
-  public function getProvider() {
-    return $this->provider;
-  }
-
 }
diff --git a/core/lib/Drupal/Core/Routing/RouteBuilder.php b/core/lib/Drupal/Core/Routing/RouteBuilder.php
index 21c80d0..5fbb48d 100644
--- a/core/lib/Drupal/Core/Routing/RouteBuilder.php
+++ b/core/lib/Drupal/Core/Routing/RouteBuilder.php
@@ -20,16 +20,13 @@
 
 /**
  * Managing class for rebuilding the router table.
- *
- * Because this class makes use of the modules system, it cannot currently
- * be unit tested.
  */
 class RouteBuilder implements RouteBuilderInterface {
 
   /**
    * The dumper to which we should send collected routes.
    *
-   * @var \Symfony\Component\Routing\Matcher\Dumper\MatcherDumperInterface
+   * @var \Drupal\Core\Routing\MatcherDumperInterface
    */
   protected $dumper;
 
@@ -69,6 +66,13 @@ class RouteBuilder implements RouteBuilderInterface {
   protected $controllerResolver;
 
   /**
+   * The route collection during the rebuild.
+   *
+   * @var \Symfony\Component\Routing\RouteCollection
+   */
+  protected $routeCollection;
+
+  /**
    * Constructs the RouteBuilder using the passed MatcherDumperInterface.
    *
    * @param \Drupal\Core\Routing\MatcherDumperInterface $dumper
@@ -81,6 +85,8 @@ class RouteBuilder implements RouteBuilderInterface {
    *   The module handler.
    * @param \Drupal\Core\Controller\ControllerResolverInterface $controller_resolver
    *   The controller resolver.
+   * @param \Drupal\Core\KeyValueStore\StateInterface $state
+   *   The state.
    */
   public function __construct(MatcherDumperInterface $dumper, LockBackendInterface $lock, EventDispatcherInterface $dispatcher, ModuleHandlerInterface $module_handler, ControllerResolverInterface $controller_resolver, StateInterface $state = NULL) {
     $this->dumper = $dumper;
@@ -103,9 +109,12 @@ public function rebuild() {
       return FALSE;
     }
 
-    foreach ($this->getRouteDefinitions() as $provider => $routes) {
-      $collection = new RouteCollection();
+    // Truncate the router table by passing dump() without any passed in routes.
+    $this->dumper->dump();
 
+    $collection = new RouteCollection();
+    $this->routeCollection = $collection;
+    foreach ($this->getRouteDefinitions() as $routes) {
       // The top-level 'routes_callback' is a list of methods in controller
       // syntax, see \Drupal\Core\Controller\ControllerResolver. These methods
       // should return a set of \Symfony\Component\Routing\Route objects, either
@@ -142,27 +151,39 @@ public function rebuild() {
         $collection->add($name, $route);
       }
 
-      $this->dispatcher->dispatch(RoutingEvents::ALTER, new RouteBuildEvent($collection, $provider));
-      $this->dumper->addRoutes($collection);
-      $this->dumper->dump(array('provider' => $provider));
     }
 
-    // Now allow modules to register additional, dynamic routes.
-    // @todo Either remove this alter or the per-provider alter.
-    $collection = new RouteCollection();
-    $this->dispatcher->dispatch(RoutingEvents::ALTER, new RouteBuildEvent($collection, 'dynamic_routes'));
+    // DYNAMIC is supposed to be used to add new routes based upon all the
+    // static defined ones.
+    $this->dispatcher->dispatch(RoutingEvents::DYNAMIC, new RouteBuildEvent($collection));
+
+    // ALTER is the final step to alter all the existing routes. We cannot stop
+    // people from adding new routes here, but we define two separate steps to
+    // make it clear.
+    $this->dispatcher->dispatch(RoutingEvents::ALTER, new RouteBuildEvent($collection));
+
     $this->dumper->addRoutes($collection);
-    $this->dumper->dump(array('provider' => 'dynamic_routes'));
+    $this->dumper->dump();
 
     $this->state->delete(static::REBUILD_NEEDED);
     $this->lock->release('router_rebuild');
     $this->dispatcher->dispatch(RoutingEvents::FINISHED, new Event());
+
+    $this->routeCollection = NULL;
+
     return TRUE;
   }
 
   /**
    * {@inheritdoc}
    */
+  public function getCollectionDuringRebuild() {
+    return $this->routeCollection ?: FALSE;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function rebuildIfNeeded() {
     if ($this->state->get(static::REBUILD_NEEDED, FALSE)) {
       return $this->rebuild();
diff --git a/core/lib/Drupal/Core/Routing/RouteBuilderInterface.php b/core/lib/Drupal/Core/Routing/RouteBuilderInterface.php
index 2c9ef24..d2f26dc 100644
--- a/core/lib/Drupal/Core/Routing/RouteBuilderInterface.php
+++ b/core/lib/Drupal/Core/Routing/RouteBuilderInterface.php
@@ -20,6 +20,13 @@
   public function rebuild();
 
   /**
+   * Returns the route collection during the rebuild.
+   *
+   * @return \Symfony\Component\Routing\RouteCollection|FALSE
+   */
+  public function getCollectionDuringRebuild();
+
+  /**
    * Rebuilds the route info and dumps to dumper if necessary.
    *
    * @return bool
diff --git a/core/lib/Drupal/Core/Routing/RouteBuilderStatic.php b/core/lib/Drupal/Core/Routing/RouteBuilderStatic.php
index 43b535a..e85cbb6 100644
--- a/core/lib/Drupal/Core/Routing/RouteBuilderStatic.php
+++ b/core/lib/Drupal/Core/Routing/RouteBuilderStatic.php
@@ -45,4 +45,8 @@ public function setRebuildNeeded() {
     $this->rebuildNeeded = TRUE;
   }
 
+  public function getCollectionDuringRebuild() {
+    return FALSE;
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Routing/RouteSubscriberBase.php b/core/lib/Drupal/Core/Routing/RouteSubscriberBase.php
index f7cf537..c935fa5 100644
--- a/core/lib/Drupal/Core/Routing/RouteSubscriberBase.php
+++ b/core/lib/Drupal/Core/Routing/RouteSubscriberBase.php
@@ -21,11 +21,8 @@
    *
    * @param \Symfony\Component\Routing\RouteCollection $collection
    *   The route collection for adding routes.
-   * @param string $provider
-   *   The provider these routes belong to. For dynamically added routes, the
-   *   provider name will be 'dynamic_routes'.
    */
-  abstract protected function alterRoutes(RouteCollection $collection, $provider);
+  abstract protected function alterRoutes(RouteCollection $collection);
 
   /**
    * {@inheritdoc}
@@ -43,7 +40,7 @@ public static function getSubscribedEvents() {
    */
   public function onAlterRoutes(RouteBuildEvent $event) {
     $collection = $event->getRouteCollection();
-    $this->alterRoutes($collection, $event->getProvider());
+    $this->alterRoutes($collection);
   }
 
 }
diff --git a/core/lib/Drupal/Core/Routing/RoutingEvents.php b/core/lib/Drupal/Core/Routing/RoutingEvents.php
index b5ee212..8df9698 100644
--- a/core/lib/Drupal/Core/Routing/RoutingEvents.php
+++ b/core/lib/Drupal/Core/Routing/RoutingEvents.php
@@ -13,13 +13,16 @@
 final class RoutingEvents {
 
   /**
+   * THE DYNAMIC event is fired on a route collection to allow new routes.
+   *
+   * This event is used to add new routes based upon existing routes.
+   */
+  const DYNAMIC = 'routing.route_dynamic';
+
+  /**
    * The ALTER event is fired on a route collection to allow changes to routes.
    *
    * This event is used to process new routes before they get saved.
-   *
-   * @see \Drupal\Core\Routing\RouteBuildEvent
-   *
-   * @var string
    */
   const ALTER = 'routing.route_alter';
 
diff --git a/core/modules/config_translation/lib/Drupal/config_translation/ConfigMapperInterface.php b/core/modules/config_translation/lib/Drupal/config_translation/ConfigMapperInterface.php
index b572708..28fb744 100644
--- a/core/modules/config_translation/lib/Drupal/config_translation/ConfigMapperInterface.php
+++ b/core/modules/config_translation/lib/Drupal/config_translation/ConfigMapperInterface.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Language\Language;
 use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\Routing\RouteCollection;
 
 /**
  * Defines an interface for configuration mapper.
@@ -24,6 +25,14 @@
   public function getTitle();
 
   /**
+   * Sets the route collection.
+   *
+   * @param \Symfony\Component\Routing\RouteCollection $collection
+   *   The route collection.
+   */
+  public function setRouteCollection(RouteCollection $collection);
+
+  /**
    * Returns the name of the base route the mapper is attached to.
    *
    * @return string
diff --git a/core/modules/config_translation/lib/Drupal/config_translation/ConfigMapperManager.php b/core/modules/config_translation/lib/Drupal/config_translation/ConfigMapperManager.php
index bdfbe55..91d1039 100644
--- a/core/modules/config_translation/lib/Drupal/config_translation/ConfigMapperManager.php
+++ b/core/modules/config_translation/lib/Drupal/config_translation/ConfigMapperManager.php
@@ -21,6 +21,7 @@
 use Drupal\Core\Plugin\Discovery\ContainerDerivativeDiscoveryDecorator;
 use Drupal\Core\Plugin\Factory\ContainerFactory;
 use Drupal\Core\TypedData\TypedDataInterface;
+use Symfony\Component\Routing\RouteCollection;
 
 /**
  * Manages plugins for configuration translation mappers.
@@ -94,10 +95,13 @@ public function __construct(CacheBackendInterface $cache_backend, LanguageManage
   /**
    * {@inheritdoc}
    */
-  public function getMappers() {
+  public function getMappers(RouteCollection $collection = NULL) {
     $mappers = array();
     foreach($this->getDefinitions() as $id => $definition) {
       $mappers[$id] = $this->createInstance($id);
+      if ($collection) {
+        $mappers[$id]->setRouteCollection($collection);
+      }
     }
 
     return $mappers;
diff --git a/core/modules/config_translation/lib/Drupal/config_translation/ConfigMapperManagerInterface.php b/core/modules/config_translation/lib/Drupal/config_translation/ConfigMapperManagerInterface.php
index 693f25b..8f72f07 100644
--- a/core/modules/config_translation/lib/Drupal/config_translation/ConfigMapperManagerInterface.php
+++ b/core/modules/config_translation/lib/Drupal/config_translation/ConfigMapperManagerInterface.php
@@ -8,6 +8,7 @@
 namespace Drupal\config_translation;
 
 use Drupal\Component\Plugin\PluginManagerInterface;
+use Symfony\Component\Routing\RouteCollection;
 
 /**
  * Provides a common interface for config mapper managers.
@@ -17,10 +18,13 @@
   /**
    * Returns an array of all mappers.
    *
+   * @param \Symfony\Component\Routing\RouteCollection $collection
+   *   The route collection used to initialize the mappers.
+   *
    * @return \Drupal\config_translation\ConfigMapperInterface[]
    *   An array of all mappers.
    */
-  public function getMappers();
+  public function getMappers(RouteCollection $collection = NULL);
 
   /**
    * Returns TRUE if the configuration data has translatable items.
diff --git a/core/modules/config_translation/lib/Drupal/config_translation/ConfigNamesMapper.php b/core/modules/config_translation/lib/Drupal/config_translation/ConfigNamesMapper.php
index 9dc32bb..89d44ef 100644
--- a/core/modules/config_translation/lib/Drupal/config_translation/ConfigNamesMapper.php
+++ b/core/modules/config_translation/lib/Drupal/config_translation/ConfigNamesMapper.php
@@ -17,6 +17,7 @@
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\Routing\Route;
+use Symfony\Component\Routing\RouteCollection;
 
 /**
  * Configuration mapper base implementation.
@@ -52,6 +53,13 @@ class ConfigNamesMapper extends PluginBase implements ConfigMapperInterface, Con
   protected $baseRoute;
 
   /**
+   * The available routes.
+   *
+   * @var \Symfony\Component\Routing\RouteCollection
+   */
+  protected $routeCollection;
+
+  /**
    * The language code of the language this mapper, if any.
    *
    * @var string|null
@@ -91,14 +99,13 @@ class ConfigNamesMapper extends PluginBase implements ConfigMapperInterface, Con
   public function __construct($plugin_id, $plugin_definition, ConfigFactoryInterface $config_factory, LocaleConfigManager $locale_config_manager, ConfigMapperManagerInterface $config_mapper_manager, RouteProviderInterface $route_provider, TranslationInterface $translation_manager) {
     $this->pluginId = $plugin_id;
     $this->pluginDefinition = $plugin_definition;
+    $this->routeProvider = $route_provider;
 
     $this->configFactory = $config_factory;
     $this->localeConfigManager = $locale_config_manager;
     $this->configMapperManager = $config_mapper_manager;
 
     $this->setTranslationManager($translation_manager);
-
-    $this->baseRoute = $route_provider->getRouteByName($this->getBaseRouteName());
   }
 
   /**
@@ -121,6 +128,13 @@ public static function create(ContainerInterface $container, array $configuratio
   /**
    * {@inheritdoc}
    */
+  public function setRouteCollection(RouteCollection $collection) {
+    $this->routeCollection = $collection;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function getTitle() {
     // A title from a *.config_translation.yml. Should be translated for
     // display in the current page language.
@@ -145,7 +159,12 @@ public function getBaseRouteParameters() {
    * {@inheritdoc}
    */
   public function getBaseRoute() {
-    return $this->baseRoute;
+    if ($this->routeCollection) {
+      return $this->routeCollection->get($this->getBaseRouteName());
+    }
+    else {
+      return $this->routeProvider->getRouteByName($this->getBaseRouteName());
+    }
   }
 
   /**
diff --git a/core/modules/config_translation/lib/Drupal/config_translation/Routing/RouteSubscriber.php b/core/modules/config_translation/lib/Drupal/config_translation/Routing/RouteSubscriber.php
index 335faa5..d9d56ad 100644
--- a/core/modules/config_translation/lib/Drupal/config_translation/Routing/RouteSubscriber.php
+++ b/core/modules/config_translation/lib/Drupal/config_translation/Routing/RouteSubscriber.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Routing\RouteSubscriberBase;
 use Drupal\config_translation\ConfigMapperManagerInterface;
+use Drupal\Core\Routing\RoutingEvents;
 use Symfony\Component\Routing\RouteCollection;
 
 /**
@@ -36,15 +37,9 @@ public function __construct(ConfigMapperManagerInterface $mapper_manager) {
   /**
    * {@inheritdoc}
    */
-  protected function alterRoutes(RouteCollection $collection, $provider) {
-    // @todo \Drupal\config_translation\ConfigNamesMapper uses the route
-    //   provider directly, which is unsafe during rebuild. This currently only
-    //   works by coincidence; fix in https://drupal.org/node/2158571.
-    if ($provider != 'dynamic_routes') {
-      return;
-    }
+  protected function alterRoutes(RouteCollection $collection) {
+    $mappers = $this->mapperManager->getMappers($collection);
 
-    $mappers = $this->mapperManager->getMappers();
     foreach ($mappers as $mapper) {
       $collection->add($mapper->getOverviewRouteName(), $mapper->getOverviewRoute());
       $collection->add($mapper->getAddRouteName(), $mapper->getAddRoute());
@@ -53,4 +48,13 @@ protected function alterRoutes(RouteCollection $collection, $provider) {
     }
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public static function getSubscribedEvents() {
+    // Come after field_ui.
+    $events[RoutingEvents::ALTER] = array('onAlterRoutes', -110);
+    return $events;
+  }
+
 }
diff --git a/core/modules/config_translation/tests/Drupal/config_translation/Tests/ConfigEntityMapperTest.php b/core/modules/config_translation/tests/Drupal/config_translation/Tests/ConfigEntityMapperTest.php
index b7ed1f5..965f373 100644
--- a/core/modules/config_translation/tests/Drupal/config_translation/Tests/ConfigEntityMapperTest.php
+++ b/core/modules/config_translation/tests/Drupal/config_translation/Tests/ConfigEntityMapperTest.php
@@ -66,7 +66,7 @@ public function setUp() {
     $this->routeProvider = $this->getMock('Drupal\Core\Routing\RouteProviderInterface');
 
     $this->routeProvider
-      ->expects($this->once())
+      ->expects($this->any())
       ->method('getRouteByName')
       ->with('language.edit')
       ->will($this->returnValue(new Route('/admin/config/regional/language/edit/{language_entity}')));
diff --git a/core/modules/config_translation/tests/Drupal/config_translation/Tests/ConfigNamesMapperTest.php b/core/modules/config_translation/tests/Drupal/config_translation/Tests/ConfigNamesMapperTest.php
index 6f45771..41a6b1a 100644
--- a/core/modules/config_translation/tests/Drupal/config_translation/Tests/ConfigNamesMapperTest.php
+++ b/core/modules/config_translation/tests/Drupal/config_translation/Tests/ConfigNamesMapperTest.php
@@ -97,7 +97,7 @@ public function setUp() {
     $this->baseRoute = new Route('/admin/config/system/site-information');
 
     $this->routeProvider
-      ->expects($this->once())
+      ->expects($this->any())
       ->method('getRouteByName')
       ->with('system.site_information_settings')
       ->will($this->returnValue($this->baseRoute));
diff --git a/core/modules/content_translation/lib/Drupal/content_translation/Routing/ContentTranslationRouteSubscriber.php b/core/modules/content_translation/lib/Drupal/content_translation/Routing/ContentTranslationRouteSubscriber.php
index cab9ac4..8b89d27 100644
--- a/core/modules/content_translation/lib/Drupal/content_translation/Routing/ContentTranslationRouteSubscriber.php
+++ b/core/modules/content_translation/lib/Drupal/content_translation/Routing/ContentTranslationRouteSubscriber.php
@@ -38,7 +38,7 @@ public function __construct(ContentTranslationManagerInterface $content_translat
   /**
    * {@inheritdoc}
    */
-  protected function alterRoutes(RouteCollection $collection, $provider) {
+  protected function alterRoutes(RouteCollection $collection) {
     foreach ($this->contentTranslationManager->getSupportedEntityTypes() as $entity_type_id => $entity_type) {
       // Try to get the route from the current collection.
       if (!$entity_route = $collection->get($entity_type->getLinkTemplate('canonical'))) {
diff --git a/core/modules/field_ui/lib/Drupal/field_ui/Routing/RouteSubscriber.php b/core/modules/field_ui/lib/Drupal/field_ui/Routing/RouteSubscriber.php
index 36456ed..c8de23f 100644
--- a/core/modules/field_ui/lib/Drupal/field_ui/Routing/RouteSubscriber.php
+++ b/core/modules/field_ui/lib/Drupal/field_ui/Routing/RouteSubscriber.php
@@ -38,7 +38,7 @@ public function __construct(EntityManagerInterface $manager) {
   /**
    * {@inheritdoc}
    */
-  protected function alterRoutes(RouteCollection $collection, $provider) {
+  protected function alterRoutes(RouteCollection $collection) {
     foreach ($this->manager->getDefinitions() as $entity_type_id => $entity_type) {
       $defaults = array();
       if ($entity_type->isFieldable() && $entity_type->hasLinkTemplate('admin-form')) {
diff --git a/core/modules/node/lib/Drupal/node/EventSubscriber/NodeAdminRouteSubscriber.php b/core/modules/node/lib/Drupal/node/EventSubscriber/NodeAdminRouteSubscriber.php
index 45cfa3d..4b5fcb0 100644
--- a/core/modules/node/lib/Drupal/node/EventSubscriber/NodeAdminRouteSubscriber.php
+++ b/core/modules/node/lib/Drupal/node/EventSubscriber/NodeAdminRouteSubscriber.php
@@ -36,7 +36,7 @@ public function __construct(ConfigFactoryInterface $config_factory) {
   /**
    * {@inheritdoc}
    */
-  protected function alterRoutes(RouteCollection $collection, $provider) {
+  protected function alterRoutes(RouteCollection $collection) {
     if ($this->configFactory->get('node.settings')->get('use_admin_theme')) {
       foreach ($collection->all() as $route) {
         if ($route->hasOption('_node_operation_route')) {
diff --git a/core/modules/rest/lib/Drupal/rest/Plugin/Derivative/EntityDerivative.php b/core/modules/rest/lib/Drupal/rest/Plugin/Derivative/EntityDerivative.php
index 8b31ed2..fc62ede 100644
--- a/core/modules/rest/lib/Drupal/rest/Plugin/Derivative/EntityDerivative.php
+++ b/core/modules/rest/lib/Drupal/rest/Plugin/Derivative/EntityDerivative.php
@@ -9,6 +9,8 @@
 
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Plugin\Discovery\ContainerDerivativeInterface;
+use Drupal\Core\Routing\RouteBuilder;
+use Drupal\Core\Routing\RouteBuilderInterface;
 use Drupal\Core\Routing\RouteProviderInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\Routing\Exception\RouteNotFoundException;
@@ -40,16 +42,26 @@ class EntityDerivative implements ContainerDerivativeInterface {
   protected $routeProvider;
 
   /**
+   * The route builder.
+   *
+   * @var \Drupal\Core\Routing\RouteBuilderInterface
+   */
+  protected $routeBuilder;
+
+  /**
    * Constructs an EntityDerivative object.
    *
    * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
    *   The entity manager.
    * @param \Drupal\Core\Routing\RouteProviderInterface $route_provider
    *   The route provider.
+   * @param \Drupal\Core\Routing\RouteBuilderInterface $route_builder
+   *   The route builder.
    */
-  public function __construct(EntityManagerInterface $entity_manager, RouteProviderInterface $route_provider) {
+  public function __construct(EntityManagerInterface $entity_manager, RouteProviderInterface $route_provider, RouteBuilderInterface $route_builder) {
     $this->entityManager = $entity_manager;
     $this->routeProvider = $route_provider;
+    $this->routeBuilder = $route_builder;
   }
 
   /**
@@ -58,7 +70,8 @@ public function __construct(EntityManagerInterface $entity_manager, RouteProvide
   public static function create(ContainerInterface $container, $base_plugin_id) {
     return new static(
       $container->get('entity.manager'),
-      $container->get('router.route_provider')
+      $container->get('router.route_provider'),
+      $container->get('router.builder')
     );
   }
 
@@ -104,12 +117,17 @@ public function getDerivativeDefinitions($base_plugin_definition) {
               $this->derivatives[$entity_type_id]['uri_paths'][$link_relation] = $route->getPath();
             }
             catch (RouteNotFoundException $e) {
-              // If the route does not exist it means we are in a brittle state
-              // of module enabling/disabling, so we simply exclude this entity
-              // type.
-              unset($this->derivatives[$entity_type_id]);
-              // Continue with the next entity type;
-              continue 2;
+              if (($collection = $this->routeBuilder->getCollectionDuringRebuild()) && $route = $collection->get($route_name)) {
+                $this->derivatives[$entity_type_id]['uri_paths'][$link_relation] = $route->getPath();
+              }
+              else {
+                // If the route does not exist it means we are in a brittle state
+                // of module enabling/disabling, so we simply exclude this entity
+                // type.
+                unset($this->derivatives[$entity_type_id]);
+                // Continue with the next entity type;
+                continue 2;
+              }
             }
           }
           else {
diff --git a/core/modules/rest/lib/Drupal/rest/RequestHandler.php b/core/modules/rest/lib/Drupal/rest/RequestHandler.php
index 20aaf5d..a5551b2 100644
--- a/core/modules/rest/lib/Drupal/rest/RequestHandler.php
+++ b/core/modules/rest/lib/Drupal/rest/RequestHandler.php
@@ -13,6 +13,7 @@
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\HttpFoundation\Response;
 use Symfony\Component\HttpKernel\Exception\HttpException;
+use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
 use Symfony\Component\HttpKernel\Exception\UnsupportedMediaTypeHttpException;
 use Symfony\Component\Serializer\Exception\UnexpectedValueException;
 
diff --git a/core/modules/rest/lib/Drupal/rest/Routing/ResourceRoutes.php b/core/modules/rest/lib/Drupal/rest/Routing/ResourceRoutes.php
index fcea617..5605048 100644
--- a/core/modules/rest/lib/Drupal/rest/Routing/ResourceRoutes.php
+++ b/core/modules/rest/lib/Drupal/rest/Routing/ResourceRoutes.php
@@ -9,13 +9,16 @@
 
 use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
+use Drupal\Core\Routing\RouteSubscriberBase;
 use Drupal\rest\Plugin\Type\ResourcePluginManager;
 use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+use Symfony\Component\Routing\RouteCollection;
 
 /**
  * Subscriber for REST-style routes.
  */
-class ResourceRoutes implements ContainerInjectionInterface {
+class ResourceRoutes extends RouteSubscriberBase{
 
   /**
    * The plugin manager for REST plugins.
@@ -45,22 +48,13 @@ public function __construct(ResourcePluginManager $manager, ConfigFactoryInterfa
   }
 
   /**
-   * {@inheritdoc}
-   */
-  public static function create(ContainerInterface $container) {
-    return new static(
-      $container->get('plugin.manager.rest'),
-      $container->get('config.factory')
-    );
-  }
-
-  /**
-   * Returns an array of route objects.
+   * Alters existing routes for a specific collection.
    *
-   * @return \Symfony\Component\Routing\Route[]
-   *   An array of route objects.
+   * @param \Symfony\Component\Routing\RouteCollection $collection
+   *   The route collection for adding routes.
+   * @return array
    */
-  public function routes() {
+  protected function alterRoutes(RouteCollection $collection) {
     $routes = array();
     $enabled_resources = $this->config->get('rest.settings')->get('resources') ?: array();
 
@@ -97,10 +91,10 @@ public function routes() {
           // authentication provider and add the route.
           $route->setOption('_auth', $enabled_methods[$method]['supported_auth']);
           $routes["rest.$name"] = $route;
+          $collection->add("rest.$name", $route);
         }
       }
     }
-    return $routes;
   }
 
 }
diff --git a/core/modules/rest/rest.routing.yml b/core/modules/rest/rest.routing.yml
index 3017130..843dee9 100644
--- a/core/modules/rest/rest.routing.yml
+++ b/core/modules/rest/rest.routing.yml
@@ -4,6 +4,3 @@ rest.csrftoken:
     _controller: '\Drupal\rest\RequestHandler::csrfToken'
   requirements:
     _access: 'TRUE'
-
-route_callbacks:
-  -  '\Drupal\rest\Routing\ResourceRoutes::routes'
diff --git a/core/modules/rest/rest.services.yml b/core/modules/rest/rest.services.yml
index bf4a19c..e7b43f3 100644
--- a/core/modules/rest/rest.services.yml
+++ b/core/modules/rest/rest.services.yml
@@ -22,3 +22,8 @@ services:
   rest.link_manager.relation:
     class: Drupal\rest\LinkManager\RelationLinkManager
     arguments: ['@cache.default', '@entity.manager']
+  rest.resource_routes:
+    class: Drupal\rest\Routing\ResourceRoutes
+    arguments: ['@plugin.manager.rest', '@config.factory']
+    tags:
+      - { name: 'event_subscriber' }
diff --git a/core/modules/system/lib/Drupal/system/EventSubscriber/AdminRouteSubscriber.php b/core/modules/system/lib/Drupal/system/EventSubscriber/AdminRouteSubscriber.php
index ef70321..eef05e1 100644
--- a/core/modules/system/lib/Drupal/system/EventSubscriber/AdminRouteSubscriber.php
+++ b/core/modules/system/lib/Drupal/system/EventSubscriber/AdminRouteSubscriber.php
@@ -19,7 +19,7 @@ class AdminRouteSubscriber extends RouteSubscriberBase {
   /**
    * {@inheritdoc}
    */
-  protected function alterRoutes(RouteCollection $collection, $provider) {
+  protected function alterRoutes(RouteCollection $collection) {
     foreach ($collection->all() as $route) {
       if (strpos($route->getPath(), '/admin') === 0 && !$route->hasOption('_admin_route')) {
         $route->setOption('_admin_route', TRUE);
diff --git a/core/modules/system/tests/modules/router_test_directory/lib/Drupal/router_test/RouteTestSubscriber.php b/core/modules/system/tests/modules/router_test_directory/lib/Drupal/router_test/RouteTestSubscriber.php
index 39fa645..a2fcad0 100644
--- a/core/modules/system/tests/modules/router_test_directory/lib/Drupal/router_test/RouteTestSubscriber.php
+++ b/core/modules/system/tests/modules/router_test_directory/lib/Drupal/router_test/RouteTestSubscriber.php
@@ -17,12 +17,10 @@ class RouteTestSubscriber extends RouteSubscriberBase {
   /**
    * {@inheritdoc}
    */
-  protected function alterRoutes(RouteCollection $collection, $provider) {
-    if ($provider == 'router_test') {
-      $route = $collection->get('router_test.6');
-      // Change controller method from test1 to test5.
-      $route->setDefault('_content', '\Drupal\router_test\TestControllers::test5');
-    }
+  protected function alterRoutes(RouteCollection $collection) {
+    $route = $collection->get('router_test.6');
+    // Change controller method from test1 to test5.
+    $route->setDefault('_content', '\Drupal\router_test\TestControllers::test5');
   }
 
 }
diff --git a/core/modules/views/lib/Drupal/views/EventSubscriber/RouteSubscriber.php b/core/modules/views/lib/Drupal/views/EventSubscriber/RouteSubscriber.php
index adccf25..9fec99b 100644
--- a/core/modules/views/lib/Drupal/views/EventSubscriber/RouteSubscriber.php
+++ b/core/modules/views/lib/Drupal/views/EventSubscriber/RouteSubscriber.php
@@ -155,7 +155,7 @@ public function routes() {
   /**
    * {@inheritdoc}
    */
-  protected function alterRoutes(RouteCollection $collection, $provider) {
+  protected function alterRoutes(RouteCollection $collection) {
     foreach ($this->getViewsDisplayIDsWithRoute() as $pair) {
       list($view_id, $display_id) = explode('.', $pair);
       $view = $this->viewStorage->load($view_id);
diff --git a/core/tests/Drupal/Tests/Core/Routing/NullRouteBuilder.php b/core/tests/Drupal/Tests/Core/Routing/NullRouteBuilder.php
index 2631c48..55c00c8 100644
--- a/core/tests/Drupal/Tests/Core/Routing/NullRouteBuilder.php
+++ b/core/tests/Drupal/Tests/Core/Routing/NullRouteBuilder.php
@@ -15,4 +15,8 @@ public function rebuildIfNeeded() {
   public function setRebuildNeeded() {
   }
 
+  public function getCollectionDuringRebuild() {
+    return FALSE;
+  }
+
 }
diff --git a/core/tests/Drupal/Tests/Core/Routing/RouteBuilderTest.php b/core/tests/Drupal/Tests/Core/Routing/RouteBuilderTest.php
index 2aec9e0..fd777ce 100644
--- a/core/tests/Drupal/Tests/Core/Routing/RouteBuilderTest.php
+++ b/core/tests/Drupal/Tests/Core/Routing/RouteBuilderTest.php
@@ -169,15 +169,14 @@ public function testRebuildWithStaticModuleRoutes() {
       ->method('findAll')
       ->will($this->returnValue(array('test_module' => $routes)));
 
-    // Ensure that the dispatch events for altering are fired.
+    $route_collection = $routing_fixtures->sampleRouteCollection();
+    $route_build_event = new RouteBuildEvent($route_collection);
+
+    // Ensure that the alter routes events are fired.
     $this->dispatcher->expects($this->at(0))
       ->method('dispatch')
-      ->with($this->equalTo(RoutingEvents::ALTER), $this->isInstanceOf('Drupal\Core\Routing\RouteBuildEvent'));
-
-    $empty_collection = new RouteCollection();
-    $route_build_event = new RouteBuildEvent($empty_collection, 'dynamic_routes');
+      ->with(RoutingEvents::DYNAMIC, $route_build_event);
 
-    // Ensure that the alter routes events are fired.
     $this->dispatcher->expects($this->at(1))
       ->method('dispatch')
       ->with(RoutingEvents::ALTER, $route_build_event);
@@ -185,16 +184,10 @@ public function testRebuildWithStaticModuleRoutes() {
     // Ensure that the routes are set to the dumper and dumped.
     $this->dumper->expects($this->at(0))
       ->method('addRoutes')
-      ->with($routing_fixtures->sampleRouteCollection());
+      ->with($route_collection);
     $this->dumper->expects($this->at(1))
       ->method('dump')
-      ->with(array('provider' => 'test_module'));
-    $this->dumper->expects($this->at(2))
-      ->method('addRoutes')
-      ->with($empty_collection);
-    $this->dumper->expects($this->at(3))
-      ->method('dump')
-      ->with(array('provider' => 'dynamic_routes'));
+      ->with();
 
     $this->assertTrue($this->routeBuilder->rebuild());
   }
@@ -242,15 +235,13 @@ public function testRebuildWithProviderBasedRoutes() {
     $route_collection_filled->add('test_route.1', new Route('/test-route/1'));
     $route_collection_filled->add('test_route.2', new Route('/test-route/2'));
 
-    // Ensure that the dispatch events for altering are fired.
+    $route_build_event = new RouteBuildEvent($route_collection_filled);
+
+    // Ensure that the alter routes events are fired.
     $this->dispatcher->expects($this->at(0))
       ->method('dispatch')
-      ->with($this->equalTo(RoutingEvents::ALTER), $this->isInstanceOf('Drupal\Core\Routing\RouteBuildEvent'));
-
-    $empty_collection = new RouteCollection();
-    $route_build_event = new RouteBuildEvent($empty_collection, 'dynamic_routes');
+      ->with(RoutingEvents::DYNAMIC, $route_build_event);
 
-    // Ensure that the alter routes events are fired.
     $this->dispatcher->expects($this->at(1))
       ->method('dispatch')
       ->with(RoutingEvents::ALTER, $route_build_event);
@@ -260,8 +251,7 @@ public function testRebuildWithProviderBasedRoutes() {
       ->method('addRoutes')
       ->with($route_collection_filled);
     $this->dumper->expects($this->at(1))
-      ->method('dump')
-      ->with(array('provider' => 'test_module'));
+      ->method('dump');
 
     $this->assertTrue($this->routeBuilder->rebuild());
   }
