diff --git a/core/core.services.yml b/core/core.services.yml
index 9b1ab37..d817e04 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -381,7 +381,7 @@ services:
     arguments: ['@path.alias_storage', '@path.alias_whitelist', '@language_manager', '@cache.data']
   path.current:
     class: Drupal\Core\Path\CurrentPathStack
-    arguments: ['@request_stack']
+    arguments: ['@request_stack', '@event_dispatcher']
   http_client:
     class: Drupal\Core\Http\Client
     tags:
@@ -655,7 +655,7 @@ services:
     arguments: ['@current_route_match']
   router.route_provider:
     class: Drupal\Core\Routing\RouteProvider
-    arguments: ['@database', '@state', '@path.current']
+    arguments: ['@database', '@state', '@path.current', '@cache.data']
     tags:
       - { name: event_subscriber }
       - { name: backend_overridable }
@@ -955,7 +955,7 @@ services:
     class: Drupal\Core\EventSubscriber\PathSubscriber
     tags:
       - { name: event_subscriber }
-    arguments: ['@path.alias_manager', '@path_processor_manager', '@path.current']
+    arguments: ['@path.alias_manager', '@path_processor_manager', '@path.current', '@request_stack']
   route_access_response_subscriber:
     class: Drupal\Core\EventSubscriber\RouteAccessResponseSubscriber
     tags:
diff --git a/core/lib/Drupal/Core/EventSubscriber/CacheRouterRebuildSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/CacheRouterRebuildSubscriber.php
index 9589348..4ec0822 100644
--- a/core/lib/Drupal/Core/EventSubscriber/CacheRouterRebuildSubscriber.php
+++ b/core/lib/Drupal/Core/EventSubscriber/CacheRouterRebuildSubscriber.php
@@ -21,7 +21,7 @@ class CacheRouterRebuildSubscriber implements EventSubscriberInterface {
    */
   public function onRouterFinished() {
     // Requested URLs that formerly gave a 403/404 may now be valid.
-    Cache::invalidateTags(['4xx-response']);
+    Cache::invalidateTags(['4xx-response', 'route_match']);
   }
 
   /**
diff --git a/core/lib/Drupal/Core/EventSubscriber/PathSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/PathSubscriber.php
index ec24484..6fb06aa 100644
--- a/core/lib/Drupal/Core/EventSubscriber/PathSubscriber.php
+++ b/core/lib/Drupal/Core/EventSubscriber/PathSubscriber.php
@@ -10,10 +10,11 @@
 use Drupal\Core\Path\AliasManagerInterface;
 use Drupal\Core\Path\CurrentPathStack;
 use Drupal\Core\PathProcessor\InboundPathProcessorInterface;
+use Symfony\Component\HttpFoundation\RequestStack;
 use Symfony\Component\HttpKernel\HttpKernelInterface;
 use Symfony\Component\HttpKernel\KernelEvents;
-use Symfony\Component\HttpKernel\Event\GetResponseEvent;
 use Symfony\Component\HttpKernel\Event\PostResponseEvent;
+use Symfony\Component\EventDispatcher\Event;
 use Symfony\Component\EventDispatcher\EventSubscriberInterface;
 
 /**
@@ -43,35 +44,44 @@ class PathSubscriber implements EventSubscriberInterface {
   protected $currentPath;
 
   /**
+   * The request stack.
+   *
+   * @var \Symfony\Component\HttpFoundation\RequestStack;
+   */
+  protected $requestStack;
+
+  /**
    * Constructs a new PathSubscriber instance.
    *
    * @param \Drupal\Core\Path\AliasManagerInterface $alias_manager
    * @param \Drupal\Core\PathProcessor\InboundPathProcessorInterface $path_processor
    * @param \Drupal\Core\Path\CurrentPathStack $current_path
    *   The current path.
+   * @param \Symfony\Component\HttpFoundation\RequestStack
+   *   The request stack.
    */
-  public function __construct(AliasManagerInterface $alias_manager, InboundPathProcessorInterface $path_processor, CurrentPathStack $current_path) {
+  public function __construct(AliasManagerInterface $alias_manager, InboundPathProcessorInterface $path_processor, CurrentPathStack $current_path, RequestStack $request_stack) {
     $this->aliasManager = $alias_manager;
     $this->pathProcessor = $path_processor;
     $this->currentPath = $current_path;
+    $this->requestStack = $request_stack;
   }
 
   /**
    * Converts the request path to a system path.
    *
-   * @param Symfony\Component\HttpKernel\Event\GetResponseEvent $event
+   * @param Symfony\Component\EventDispatcher\Event\Event $event
    *   The Event to process.
    */
-  public function onKernelRequestConvertPath(GetResponseEvent $event) {
+  public function onIncomingPathConvertPath(Event $event) {
     $request = $event->getRequest();
     $path = trim($request->getPathInfo(), '/');
     $path = $this->pathProcessor->processInbound($path, $request);
-    $this->currentPath->setPath('/' . $path, $request);
+    $event->setPath('/' . $path);
 
-    // Set the cache key on the alias manager cache decorator.
-    if ($event->getRequestType() == HttpKernelInterface::MASTER_REQUEST) {
-      $this->aliasManager->setCacheKey($path);
-    }
+    // Set the cache key on the alias manager cache decorator when dealing with
+    // master requests.
+    $this->aliasManager->setCacheKey($path);
   }
 
   /**
@@ -88,7 +98,7 @@ public function onKernelTerminate(PostResponseEvent $event) {
    *   An array of event listener definitions.
    */
   static function getSubscribedEvents() {
-    $events[KernelEvents::REQUEST][] = array('onKernelRequestConvertPath', 200);
+    $events['incoming_path'][] = array('onIncomingPathConvertPath', 200);
     $events[KernelEvents::TERMINATE][] = array('onKernelTerminate', 200);
     return $events;
   }
diff --git a/core/lib/Drupal/Core/Path/CurrentPathStack.php b/core/lib/Drupal/Core/Path/CurrentPathStack.php
index d7abdb1..9ab3c3b 100644
--- a/core/lib/Drupal/Core/Path/CurrentPathStack.php
+++ b/core/lib/Drupal/Core/Path/CurrentPathStack.php
@@ -6,6 +6,8 @@
  */
 
 namespace Drupal\Core\Path;
+use Drupal\Core\Path\InboundPathEvent;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 use Symfony\Component\HttpFoundation\RequestStack;
 
 /**
@@ -32,13 +34,23 @@ class CurrentPathStack {
   protected $requestStack;
 
   /**
+   * The event dispatcher.
+   *
+   * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
+   */
+  protected $eventDispatcher;
+
+  /**
    * Constructs a new CurrentPathStack instance.
    *
    * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
    *   The request stack.
+   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface
+   *   The event dispatcher.
    */
-  public function __construct(RequestStack $request_stack) {
+  public function __construct(RequestStack $request_stack, $event_dispatcher) {
     $this->requestStack = $request_stack;
+    $this->eventDispatcher = $event_dispatcher;
     $this->paths = new \SplObjectStorage();
   }
 
@@ -56,7 +68,10 @@ public function getPath($request = NULL) {
       $request = $this->requestStack->getCurrentRequest();
     }
     if (!isset($this->paths[$request])) {
-      $this->paths[$request] = $request->getPathInfo();
+      $event = new InboundPathEvent();
+      $event->setRequest($request);
+      $this->eventDispatcher->dispatch('incoming_path', $event);
+      $this->paths[$request] = $event->getPath();
     }
 
     return $this->paths[$request];
diff --git a/core/lib/Drupal/Core/Path/InboundPathEvent.php b/core/lib/Drupal/Core/Path/InboundPathEvent.php
new file mode 100644
index 0000000..0ce6512
--- /dev/null
+++ b/core/lib/Drupal/Core/Path/InboundPathEvent.php
@@ -0,0 +1,27 @@
+<?php
+
+namespace Drupal\Core\Path;
+
+use \Symfony\Component\EventDispatcher\Event;
+
+class InboundPathEvent extends Event {
+
+  protected $path;
+
+
+  public function setPath($path) {
+    $this->path = $path;
+  }
+
+  public function getPath() {
+    return $this->path;
+  }
+
+  public function setRequest($request) {
+    $this->request = $request;
+  }
+
+  public function getRequest() {
+    return $this->request;
+  }
+}
diff --git a/core/lib/Drupal/Core/Routing/RouteProvider.php b/core/lib/Drupal/Core/Routing/RouteProvider.php
index 8f98802..1a9d3f1 100644
--- a/core/lib/Drupal/Core/Routing/RouteProvider.php
+++ b/core/lib/Drupal/Core/Routing/RouteProvider.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\Core\Routing;
 
+use Drupal\Core\Cache\CacheBackendInterface;
 use Drupal\Core\Path\CurrentPathStack;
 use Drupal\Core\State\StateInterface;
 use Symfony\Cmf\Component\Routing\PagedRouteCollection;
@@ -67,6 +68,13 @@ class RouteProvider implements PreloadableRouteProviderInterface, PagedRouteProv
   protected $currentPath;
 
   /**
+   * The cache backend.
+   *
+   * @var \Drupal\Core\Cache\CacheBackendInterface
+   */
+  protected $cache;
+
+  /**
    * Constructs a new PathMatcher.
    *
    * @param \Drupal\Core\Database\Connection $connection
@@ -74,15 +82,18 @@ class RouteProvider implements PreloadableRouteProviderInterface, PagedRouteProv
    * @param \Drupal\Core\State\StateInterface $state
    *   The state.
    * @param \Drupal\Core\Path\CurrentPathStack $current_path
-   *   THe current path.
+   *   The current path.
+   * @param \Drupal\Core\Cache\CacheBackendInterface
+   *   The cache backend.
    * @param string $table
    *   The table in the database to use for matching.
    */
-  public function __construct(Connection $connection, StateInterface $state, CurrentPathStack $current_path, $table = 'router') {
+  public function __construct(Connection $connection, StateInterface $state, CurrentPathStack $current_path, CacheBackendInterface $cache_backend, $table = 'router') {
     $this->connection = $connection;
     $this->state = $state;
     $this->tableName = $table;
     $this->currentPath = $current_path;
+    $this->cache = $cache_backend;
   }
 
   /**
@@ -111,9 +122,17 @@ public function __construct(Connection $connection, StateInterface $state, Curre
    * @todo Should this method's found routes also be included in the cache?
    */
   public function getRouteCollectionForRequest(Request $request) {
-    $path = $this->currentPath->getPath($request);
-
-    return $this->getRoutesByPath(rtrim($path, '/'));
+    $cid = 'route:' . $request->getPathInfo();
+    if ($cached = $this->cache->get($cid)) {
+      $this->currentPath->setPath($cached->data[0], $request);
+      return $cached->data[1];
+    }
+    else {
+      $path = $this->currentPath->getPath($request);
+      $routes = $this->getRoutesByPath(rtrim($path, '/'));
+      $this->cache->set($cid, [$path, $routes], CacheBackendInterface::CACHE_PERMANENT, ['route_match']);
+      return $routes;
+    }
   }
 
   /**
