diff --git a/core/core.services.yml b/core/core.services.yml
index 402d6ee..51a42bd 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -342,8 +342,6 @@ services:
     class: Drupal\Core\ParamConverter\ParamConverterManager
     calls:
       - [setContainer, ['@service_container']]
-    tags:
-      - { name: route_enhancer }
   paramconverter_subscriber:
     class: Drupal\Core\EventSubscriber\ParamConverterSubscriber
     tags:
@@ -373,6 +371,11 @@ services:
     class: Drupal\Core\EventSubscriber\AjaxResponseSubscriber
     tags:
       - { name: event_subscriber }
+  route_enhancer.param_conversion:
+    class: Drupal\Core\Routing\Enhancer\ParamConversionEnhancer
+    arguments: ['@paramconverter_manager']
+    tags:
+      - { name: route_enhancer }
   route_enhancer.authentication:
     class: Drupal\Core\Routing\Enhancer\AuthenticationEnhancer
     calls:
@@ -447,7 +450,7 @@ services:
       - [setCurrentUser, ['@?current_user']]
   access_manager:
     class: Drupal\Core\Access\AccessManager
-    arguments: ['@router.route_provider', '@url_generator', '@paramconverter_manager']
+    arguments: ['@router.route_provider', '@url_generator', '@route_enhancer.param_conversion']
     calls:
       - [setContainer, ['@service_container']]
       - [setRequest, ['@?request']]
diff --git a/core/includes/menu.inc b/core/includes/menu.inc
index bbf5c43..96f810e 100644
--- a/core/includes/menu.inc
+++ b/core/includes/menu.inc
@@ -9,13 +9,13 @@
 use Drupal\Component\Utility\String;
 use Drupal\Core\Cache\Cache;
 use Drupal\Core\Language\Language;
+use Drupal\Core\ParamConverter\ParamNotConvertedException;
 use Drupal\Core\Routing\RequestHelper;
 use Drupal\Core\Template\Attribute;
 use Drupal\menu_link\Entity\MenuLink;
 use Drupal\menu_link\MenuLinkStorageController;
 use Symfony\Cmf\Component\Routing\RouteObjectInterface;
 use Symfony\Component\HttpFoundation\Request;
-use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
 use Symfony\Component\Routing\Route;
 
 /**
@@ -934,7 +934,7 @@ function menu_item_route_access(Route $route, $href, &$map, Request $request = N
   try {
     $request->attributes->add(\Drupal::service('router')->matchRequest($request));
   }
-  catch (NotFoundHttpException $e) {
+  catch (ParamNotConvertedException $e) {
     return FALSE;
   }
 
diff --git a/core/lib/Drupal/Core/Access/AccessManager.php b/core/lib/Drupal/Core/Access/AccessManager.php
index 3bb2194..c6b5155 100644
--- a/core/lib/Drupal/Core/Access/AccessManager.php
+++ b/core/lib/Drupal/Core/Access/AccessManager.php
@@ -8,10 +8,12 @@
 namespace Drupal\Core\Access;
 
 use Drupal\Core\ParamConverter\ParamConverterManager;
+use Drupal\Core\ParamConverter\ParamNotConvertedException;
 use Drupal\Core\Routing\Access\AccessInterface as RoutingAccessInterface;
 use Drupal\Core\Routing\RequestHelper;
 use Drupal\Core\Routing\RouteProviderInterface;
 use Drupal\Core\Session\AccountInterface;
+use Symfony\Cmf\Component\Routing\Enhancer\RouteEnhancerInterface;
 use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
 use Symfony\Component\Routing\RouteCollection;
 use Symfony\Component\Routing\Route;
@@ -71,11 +73,11 @@ class AccessManager extends ContainerAware {
   protected $urlGenerator;
 
   /**
-   * The paramconverter manager.
+   * The route enhancer.
    *
-   * @var \Drupal\Core\ParamConverter\ParamConverterManager
+   * @var \Symfony\Cmf\Component\Routing\Enhancer\RouteEnhancerInterface
    */
-  protected $paramConverterManager;
+  protected $routeEnhancer;
 
   /**
    * A request object.
@@ -91,13 +93,13 @@ class AccessManager extends ContainerAware {
    *   The route provider.
    * @param \Symfony\Component\Routing\Generator\UrlGeneratorInterface $url_generator
    *   The url generator.
-   * @param \Drupal\Core\ParamConverter\ParamConverterManager $paramconverter_manager
-   *   The param converter manager.
+   * @param \Symfony\Cmf\Component\Routing\Enhancer\RouteEnhancerInterface $route_enhancer
+   *   The route enhancer.
    */
-  public function __construct(RouteProviderInterface $route_provider, UrlGeneratorInterface $url_generator, ParamConverterManager $paramconverter_manager) {
+  public function __construct(RouteProviderInterface $route_provider, UrlGeneratorInterface $url_generator, RouteEnhancerInterface $route_enhancer) {
     $this->routeProvider = $route_provider;
     $this->urlGenerator = $url_generator;
-    $this->paramConverterManager = $paramconverter_manager;
+    $this->routeEnhancer = $route_enhancer;
   }
 
   /**
@@ -202,14 +204,14 @@ public function checkNamedRoute($route_name, array $parameters = array(), Accoun
         $defaults = $parameters + $route->getDefaults();
         $route_request = RequestHelper::duplicate($this->request, $this->urlGenerator->generate($route_name, $defaults));
         $defaults[RouteObjectInterface::ROUTE_OBJECT] = $route;
-        $route_request->attributes->add($this->paramConverterManager->enhance($defaults, $route_request));
+        $route_request->attributes->add($this->routeEnhancer->enhance($defaults, $route_request));
       }
       return $this->check($route, $route_request, $account);
     }
     catch (RouteNotFoundException $e) {
       return FALSE;
     }
-    catch (NotFoundHttpException $e) {
+    catch (ParamNotConvertedException $e) {
       return FALSE;
     }
   }
diff --git a/core/lib/Drupal/Core/ParamConverter/ParamConverterManager.php b/core/lib/Drupal/Core/ParamConverter/ParamConverterManager.php
index cad587b..8061522 100644
--- a/core/lib/Drupal/Core/ParamConverter/ParamConverterManager.php
+++ b/core/lib/Drupal/Core/ParamConverter/ParamConverterManager.php
@@ -8,12 +8,7 @@
 namespace Drupal\Core\ParamConverter;
 
 use Symfony\Component\DependencyInjection\ContainerAware;
-use Symfony\Cmf\Component\Routing\Enhancer\RouteEnhancerInterface;
-use Symfony\Cmf\Component\Routing\RouteObjectInterface;
-use Symfony\Component\HttpFoundation\ParameterBag;
-use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
 use Symfony\Component\Routing\RouteCollection;
-use Symfony\Component\HttpFoundation\Request;
 
 /**
  * Manages converter services for converting request parameters to full objects.
@@ -21,7 +16,7 @@
  * A typical use case for this would be upcasting (converting) a node id to a
  * node entity.
  */
-class ParamConverterManager extends ContainerAware implements RouteEnhancerInterface {
+class ParamConverterManager extends ContainerAware {
 
   /**
    * An array of registered converter service ids.
@@ -136,62 +131,5 @@ public function setRouteParameterConverters(RouteCollection $routes) {
     }
   }
 
-  /**
-   * Invokes the registered converter for each defined parameter on a route.
-   *
-   * @param array $defaults
-   *   The route defaults array.
-   * @param \Symfony\Component\HttpFoundation\Request $request
-   *   The current request.
-   *
-   * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
-   *   If one of the assigned converters returned NULL because the given
-   *   variable could not be converted.
-   *
-   * @return array
-   *   The modified defaults.
-   */
-  public function enhance(array $defaults, Request $request) {
-    // Store a backup of the raw $defaults values corresponding to
-    // variables in the route path pattern.
-    $route = $defaults[RouteObjectInterface::ROUTE_OBJECT];
-    $variables = array_flip($route->compile()->getVariables());
-    // Foreach  will copy the values from the array it iterates. Even if they
-    // are references, use it to break them. This avoids any scenarios where raw
-    // variables also get replaced with converted values.
-    $raw_variables = array();
-    foreach (array_intersect_key($defaults, $variables) as $key => $value) {
-      $raw_variables[$key] = $value;
-    }
-    $defaults['_raw_variables'] = new ParameterBag($raw_variables);
-
-    // Skip this enhancer if there are no parameter definitions.
-    if (!$parameters = $route->getOption('parameters')) {
-      return $defaults;
-    }
-
-    // Invoke the registered converter for each parameter.
-    foreach ($parameters as $name => $definition) {
-      if (!isset($defaults[$name])) {
-        // Do not try to convert anything that is already set to NULL.
-        continue;
-      }
-
-      if (!isset($definition['converter'])) {
-        // Continue if no converter has been specified.
-        continue;
-      }
-
-      // If a converter returns NULL it means that the parameter could not be
-      // converted in which case we throw a 404.
-      $defaults[$name] = $this->getConverter($definition['converter'])->convert($defaults[$name], $definition, $name, $defaults, $request);
-      if (!isset($defaults[$name])) {
-        throw new NotFoundHttpException();
-      }
-    }
-
-    return $defaults;
-  }
-
 }
 
diff --git a/core/lib/Drupal/Core/ParamConverter/ParamNotConvertedException.php b/core/lib/Drupal/Core/ParamConverter/ParamNotConvertedException.php
new file mode 100644
index 0000000..11ed70f
--- /dev/null
+++ b/core/lib/Drupal/Core/ParamConverter/ParamNotConvertedException.php
@@ -0,0 +1,15 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\ParamConverter\ParamNotConvertedException.
+ */
+
+namespace Drupal\Core\ParamConverter;
+
+/**
+ * Provides an exception class for a request parameter that was not converted.
+ */
+class ParamNotConvertedException extends \Exception {
+
+}
diff --git a/core/lib/Drupal/Core/Routing/Enhancer/ParamConversionEnhancer.php b/core/lib/Drupal/Core/Routing/Enhancer/ParamConversionEnhancer.php
new file mode 100644
index 0000000..55b4392
--- /dev/null
+++ b/core/lib/Drupal/Core/Routing/Enhancer/ParamConversionEnhancer.php
@@ -0,0 +1,80 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Routing\Enhancer\ParamConversionEnhancer.
+ */
+
+namespace Drupal\Core\Routing\Enhancer;
+
+use Drupal\Core\ParamConverter\ParamConverterManager;
+use Drupal\Core\ParamConverter\ParamNotConvertedException;
+use Symfony\Cmf\Component\Routing\Enhancer\RouteEnhancerInterface;
+use Symfony\Cmf\Component\Routing\RouteObjectInterface;
+use Symfony\Component\HttpFoundation\ParameterBag;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Provides a route enhancer that handles parameter conversion.
+ */
+class ParamConversionEnhancer implements RouteEnhancerInterface {
+
+  /**
+   * @var \Drupal\Core\ParamConverter\ParamConverterManager
+   */
+  protected $paramConverterManager;
+
+  /**
+   * @param \Drupal\Core\ParamConverter\ParamConverterManager $param_converter_manager
+   */
+  public function __construct(ParamConverterManager $param_converter_manager) {
+    $this->paramConverterManager = $param_converter_manager;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function enhance(array $defaults, Request $request) {
+    // Store a backup of the raw $defaults values corresponding to
+    // variables in the route path pattern.
+    /** @var $route \Symfony\Component\Routing\Route */
+    $route = $defaults[RouteObjectInterface::ROUTE_OBJECT];
+    $variables = array_flip($route->compile()->getVariables());
+    // Foreach  will copy the values from the array it iterates. Even if they
+    // are references, use it to break them. This avoids any scenarios where raw
+    // variables also get replaced with converted values.
+    $raw_variables = array();
+    foreach (array_intersect_key($defaults, $variables) as $key => $value) {
+      $raw_variables[$key] = $value;
+    }
+    $defaults['_raw_variables'] = new ParameterBag($raw_variables);
+
+    // Skip this enhancer if there are no parameter definitions.
+    if (!$parameters = $route->getOption('parameters')) {
+      return $defaults;
+    }
+
+    // Invoke the registered converter for each parameter.
+    foreach ($parameters as $name => $definition) {
+      if (!isset($defaults[$name])) {
+        // Do not try to convert anything that is already set to NULL.
+        continue;
+      }
+
+      if (!isset($definition['converter'])) {
+        // Continue if no converter has been specified.
+        continue;
+      }
+
+      // If a converter returns NULL it means that the parameter could not be
+      // converted in which case we throw a 404.
+      $defaults[$name] = $this->paramConverterManager->getConverter($definition['converter'])->convert($defaults[$name], $definition, $name, $defaults, $request);
+      if (!isset($defaults[$name])) {
+        throw new ParamNotConvertedException(sprintf('The "%s" parameter was not converted for the path "%s"', $name, $route->getPath()));
+      }
+    }
+
+    return $defaults;
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Routing/UrlMatcher.php b/core/lib/Drupal/Core/Routing/UrlMatcher.php
index 9e973d4..9879d28 100644
--- a/core/lib/Drupal/Core/Routing/UrlMatcher.php
+++ b/core/lib/Drupal/Core/Routing/UrlMatcher.php
@@ -30,7 +30,16 @@ public function finalMatch(RouteCollection $collection, Request $request) {
     $context = new RequestContext();
     $context->fromRequest($request);
     $this->setContext($context);
-    return $this->match('/' . $request->attributes->get('_system_path'));
+    if ($request->attributes->has('_system_path')) {
+      // _system_path never has leading or trailing slashes.
+      $path = '/' . $request->attributes->get('_system_path');
+    }
+    else {
+      // getPathInfo() always has leading slash, and might or might not have a
+      // trailing slash.
+      $path = rtrim($request->getPathInfo(), '/');
+    }
+    return $this->match($path);
   }
 
   /**
diff --git a/core/modules/config_translation/lib/Drupal/config_translation/Controller/ConfigTranslationController.php b/core/modules/config_translation/lib/Drupal/config_translation/Controller/ConfigTranslationController.php
index 03c2a20..9c65218 100644
--- a/core/modules/config_translation/lib/Drupal/config_translation/Controller/ConfigTranslationController.php
+++ b/core/modules/config_translation/lib/Drupal/config_translation/Controller/ConfigTranslationController.php
@@ -13,12 +13,12 @@
 use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
 use Drupal\Core\Language\Language;
 use Drupal\Core\Language\LanguageManagerInterface;
+use Drupal\Core\ParamConverter\ParamNotConvertedException;
 use Drupal\Core\PathProcessor\InboundPathProcessorInterface;
 use Drupal\Core\Session\AccountInterface;
 use Symfony\Cmf\Component\Routing\RouteObjectInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpFoundation\Request;
-use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
 use Symfony\Component\Routing\Exception\ResourceNotFoundException;
 use Symfony\Component\Routing\Matcher\RequestMatcherInterface;
 
@@ -252,7 +252,7 @@ protected function getRequestForPath(Request $request, $path) {
       $route_request->attributes->add($this->router->matchRequest($route_request));
       return $route_request;
     }
-    catch (NotFoundHttpException $e) {
+    catch (ParamNotConvertedException $e) {
       return NULL;
     }
     catch (ResourceNotFoundException $e) {
diff --git a/core/modules/edit/lib/Drupal/edit/Access/EditEntityAccessCheck.php b/core/modules/edit/lib/Drupal/edit/Access/EditEntityAccessCheck.php
index 827c06f..3c6dbcd 100644
--- a/core/modules/edit/lib/Drupal/edit/Access/EditEntityAccessCheck.php
+++ b/core/modules/edit/lib/Drupal/edit/Access/EditEntityAccessCheck.php
@@ -44,7 +44,9 @@ public function access(Route $route, Request $request, AccountInterface $account
     // @todo Request argument validation and object loading should happen
     //   elsewhere in the request processing pipeline:
     //   http://drupal.org/node/1798214.
-    $this->validateAndUpcastRequestAttributes($request);
+    if (!$this->validateAndUpcastRequestAttributes($request)) {
+      return static::KILL;
+    }
 
     return $this->accessEditEntity($request->attributes->get('entity'), $account)  ? static::ALLOW : static::DENY;
   }
@@ -65,14 +67,16 @@ protected function validateAndUpcastRequestAttributes(Request $request) {
       $entity_id = $entity;
       $entity_type = $request->attributes->get('entity_type');
       if (!$entity_type || !$this->entityManager->getDefinition($entity_type)) {
-        throw new NotFoundHttpException();
+        return FALSE;
       }
       $entity = $this->entityManager->getStorageController($entity_type)->load($entity_id);
       if (!$entity) {
-        throw new NotFoundHttpException();
+        return FALSE;
       }
       $request->attributes->set('entity', $entity);
     }
+
+    return TRUE;
   }
 
 }
diff --git a/core/modules/edit/lib/Drupal/edit/Access/EditEntityFieldAccessCheck.php b/core/modules/edit/lib/Drupal/edit/Access/EditEntityFieldAccessCheck.php
index 9de7347..50aaf64 100644
--- a/core/modules/edit/lib/Drupal/edit/Access/EditEntityFieldAccessCheck.php
+++ b/core/modules/edit/lib/Drupal/edit/Access/EditEntityFieldAccessCheck.php
@@ -12,7 +12,6 @@
 use Drupal\Core\Session\AccountInterface;
 use Symfony\Component\Routing\Route;
 use Symfony\Component\HttpFoundation\Request;
-use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
 use Drupal\Core\Entity\EntityInterface;
 
 /**
@@ -44,7 +43,9 @@ public function access(Route $route, Request $request, AccountInterface $account
     // @todo Request argument validation and object loading should happen
     //   elsewhere in the request processing pipeline:
     //   http://drupal.org/node/1798214.
-    $this->validateAndUpcastRequestAttributes($request);
+    if (!$this->validateAndUpcastRequestAttributes($request)) {
+      return static::KILL;
+    }
 
     return $this->accessEditEntityField($request->attributes->get('entity'), $request->attributes->get('field_name'))  ? static::ALLOW : static::DENY;
   }
@@ -65,11 +66,11 @@ protected function validateAndUpcastRequestAttributes(Request $request) {
       $entity_id = $entity;
       $entity_type = $request->attributes->get('entity_type');
       if (!$entity_type || !$this->entityManager->getDefinition($entity_type)) {
-        throw new NotFoundHttpException();
+        return FALSE;
       }
       $entity = $this->entityManager->getStorageController($entity_type)->load($entity_id);
       if (!$entity) {
-        throw new NotFoundHttpException();
+        return FALSE;
       }
       $request->attributes->set('entity', $entity);
     }
@@ -77,12 +78,14 @@ protected function validateAndUpcastRequestAttributes(Request $request) {
     // Validate the field name and language.
     $field_name = $request->attributes->get('field_name');
     if (!$field_name || !$entity->hasField($field_name)) {
-      throw new NotFoundHttpException();
+      return FALSE;
     }
     $langcode = $request->attributes->get('langcode');
     if (!$langcode || !$entity->hasTranslation($langcode)) {
-      throw new NotFoundHttpException();
+      return FALSE;
     }
+
+    return TRUE;
   }
 
 }
diff --git a/core/modules/edit/tests/Drupal/edit/Tests/Access/EditEntityAccessCheckTest.php b/core/modules/edit/tests/Drupal/edit/Tests/Access/EditEntityAccessCheckTest.php
index 0d5ca57..9e8d050 100644
--- a/core/modules/edit/tests/Drupal/edit/Tests/Access/EditEntityAccessCheckTest.php
+++ b/core/modules/edit/tests/Drupal/edit/Tests/Access/EditEntityAccessCheckTest.php
@@ -117,8 +117,6 @@ public function testAccess(EntityInterface $entity, $expected_result) {
 
   /**
    * Tests the access method with an undefined entity type.
-   *
-   * @expectedException \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
    */
   public function testAccessWithUndefinedEntityType() {
     $route = new Route('/edit/form/test_entity/1/body/und/full', array(), array('_access_edit_entity' => 'TRUE'));
@@ -131,13 +129,11 @@ public function testAccessWithUndefinedEntityType() {
       ->will($this->returnValue(NULL));
 
     $account = $this->getMock('Drupal\Core\Session\AccountInterface');
-    $this->editAccessCheck->access($route, $request, $account);
+    $this->assertSame(AccessCheckInterface::KILL, $this->editAccessCheck->access($route, $request, $account));
   }
 
   /**
    * Tests the access method with a non existing entity.
-   *
-   * @expectedException \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
    */
   public function testAccessWithNotExistingEntity() {
     $route = new Route('/edit/form/test_entity/1/body/und/full', array(), array('_access_edit_entity_field' => 'TRUE'));
@@ -156,7 +152,7 @@ public function testAccessWithNotExistingEntity() {
       ->will($this->returnValue(NULL));
 
     $account = $this->getMock('Drupal\Core\Session\AccountInterface');
-    $this->editAccessCheck->access($route, $request, $account);
+    $this->assertSame(AccessCheckInterface::KILL, $this->editAccessCheck->access($route, $request, $account));
   }
 
 }
diff --git a/core/modules/edit/tests/Drupal/edit/Tests/Access/EditEntityFieldAccessCheckTest.php b/core/modules/edit/tests/Drupal/edit/Tests/Access/EditEntityFieldAccessCheckTest.php
index b9c847d..0791249 100644
--- a/core/modules/edit/tests/Drupal/edit/Tests/Access/EditEntityFieldAccessCheckTest.php
+++ b/core/modules/edit/tests/Drupal/edit/Tests/Access/EditEntityFieldAccessCheckTest.php
@@ -144,8 +144,6 @@ public function testAccess(EntityInterface $entity, FieldInterface $field = NULL
 
   /**
    * Tests the access method with an undefined entity type.
-   *
-   * @expectedException \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
    */
   public function testAccessWithUndefinedEntityType() {
     $route = new Route('/edit/form/test_entity/1/body/und/full', array(), array('_access_edit_entity_field' => 'TRUE'));
@@ -158,13 +156,11 @@ public function testAccessWithUndefinedEntityType() {
       ->will($this->returnValue(NULL));
 
     $account = $this->getMock('Drupal\Core\Session\AccountInterface');
-    $this->editAccessCheck->access($route, $request, $account);
+    $this->assertSame(AccessCheckInterface::KILL, $this->editAccessCheck->access($route, $request, $account));
   }
 
   /**
    * Tests the access method with a non existing entity.
-   *
-   * @expectedException \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
    */
   public function testAccessWithNotExistingEntity() {
     $route = new Route('/edit/form/test_entity/1/body/und/full', array(), array('_access_edit_entity_field' => 'TRUE'));
@@ -183,13 +179,11 @@ public function testAccessWithNotExistingEntity() {
       ->will($this->returnValue(NULL));
 
     $account = $this->getMock('Drupal\Core\Session\AccountInterface');
-    $this->editAccessCheck->access($route, $request, $account);
+    $this->assertSame(AccessCheckInterface::KILL, $this->editAccessCheck->access($route, $request, $account));
   }
 
   /**
    * Tests the access method with a forgotten passed field_name.
-   *
-   * @expectedException \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
    */
   public function testAccessWithNotPassedFieldName() {
     $route = new Route('/edit/form/test_entity/1/body/und/full', array(), array('_access_edit_entity_field' => 'TRUE'));
@@ -198,13 +192,11 @@ public function testAccessWithNotPassedFieldName() {
     $request->attributes->set('entity', $this->createMockEntity());
 
     $account = $this->getMock('Drupal\Core\Session\AccountInterface');
-    $this->editAccessCheck->access($route, $request, $account);
+    $this->assertSame(AccessCheckInterface::KILL, $this->editAccessCheck->access($route, $request, $account));
   }
 
   /**
    * Tests the access method with a non existing field.
-   *
-   * @expectedException \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
    */
   public function testAccessWithNonExistingField() {
     $route = new Route('/edit/form/test_entity/1/body/und/full', array(), array('_access_edit_entity_field' => 'TRUE'));
@@ -214,13 +206,11 @@ public function testAccessWithNonExistingField() {
     $request->attributes->set('field_name', 'not_valid');
 
     $account = $this->getMock('Drupal\Core\Session\AccountInterface');
-    $this->editAccessCheck->access($route, $request, $account);
+    $this->assertSame(AccessCheckInterface::KILL, $this->editAccessCheck->access($route, $request, $account));
   }
 
   /**
    * Tests the access method with a forgotten passed language.
-   *
-   * @expectedException \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
    */
   public function testAccessWithNotPassedLanguage() {
     $route = new Route('/edit/form/test_entity/1/body/und/full', array(), array('_access_edit_entity_field' => 'TRUE'));
@@ -230,13 +220,11 @@ public function testAccessWithNotPassedLanguage() {
     $request->attributes->set('field_name', 'valid');
 
     $account = $this->getMock('Drupal\Core\Session\AccountInterface');
-    $this->editAccessCheck->access($route, $request, $account);
+    $this->assertSame(AccessCheckInterface::KILL, $this->editAccessCheck->access($route, $request, $account));
   }
 
   /**
    * Tests the access method with an invalid language.
-   *
-   * @expectedException \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
    */
   public function testAccessWithInvalidLanguage() {
     $entity = $this->createMockEntity();
@@ -253,7 +241,7 @@ public function testAccessWithInvalidLanguage() {
     $request->attributes->set('langcode', 'xx-lolspeak');
 
     $account = $this->getMock('Drupal\Core\Session\AccountInterface');
-    $this->editAccessCheck->access($route, $request, $account);
+    $this->assertSame(AccessCheckInterface::KILL, $this->editAccessCheck->access($route, $request, $account));
   }
 
   /**
diff --git a/core/modules/system/lib/Drupal/system/PathBasedBreadcrumbBuilder.php b/core/modules/system/lib/Drupal/system/PathBasedBreadcrumbBuilder.php
index 4ab853c..f39a1a5 100644
--- a/core/modules/system/lib/Drupal/system/PathBasedBreadcrumbBuilder.php
+++ b/core/modules/system/lib/Drupal/system/PathBasedBreadcrumbBuilder.php
@@ -12,10 +12,10 @@
 use Drupal\Core\Controller\TitleResolverInterface;
 use Drupal\Core\Access\AccessManager;
 use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\ParamConverter\ParamNotConvertedException;
 use Drupal\Core\PathProcessor\InboundPathProcessorInterface;
 use Drupal\Component\Utility\Unicode;
 use Symfony\Component\HttpFoundation\Request;
-use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
 use Symfony\Cmf\Component\Routing\RouteObjectInterface;
 use Symfony\Component\Routing\Matcher\RequestMatcherInterface;
 use Symfony\Component\Routing\Exception\ResourceNotFoundException;
@@ -192,7 +192,7 @@ protected function getRequestForPath($path, array $exclude) {
       $request->attributes->add($this->router->matchRequest($request));
       return $request;
     }
-    catch (NotFoundHttpException $e) {
+    catch (ParamNotConvertedException $e) {
       return NULL;
     }
     catch (ResourceNotFoundException $e) {
diff --git a/core/modules/system/lib/Drupal/system/Tests/Routing/RouterTest.php b/core/modules/system/lib/Drupal/system/Tests/Routing/RouterTest.php
index 25d3de0..2ce0f87 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Routing/RouterTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Routing/RouterTest.php
@@ -149,6 +149,20 @@ public function testUrlGeneratorFront() {
   }
 
   /**
+   * Tests that a page trying to match a path will succeed.
+   */
+  public function testRouterMatching() {
+    $this->drupalGet('router_test/test14/1');
+    $this->assertResponse(200);
+    $this->assertText('User route "user.view" was matched.');
+
+    // Try to match a route for a non-existent user.
+    $this->drupalGet('router_test/test14/2');
+    $this->assertResponse(200);
+    $this->assertText('Route not matched.');
+  }
+
+  /**
    * Tests the user account on the DIC.
    */
   public function testUserAccount() {
diff --git a/core/modules/system/tests/modules/router_test_directory/lib/Drupal/router_test/TestControllers.php b/core/modules/system/tests/modules/router_test_directory/lib/Drupal/router_test/TestControllers.php
index 86342d5..0db6826 100644
--- a/core/modules/system/tests/modules/router_test_directory/lib/Drupal/router_test/TestControllers.php
+++ b/core/modules/system/tests/modules/router_test_directory/lib/Drupal/router_test/TestControllers.php
@@ -7,6 +7,9 @@
 
 namespace Drupal\router_test;
 
+use Drupal\Core\ParamConverter\ParamNotConvertedException;
+use Drupal\user\UserInterface;
+use Symfony\Cmf\Component\Routing\RouteObjectInterface;
 use Symfony\Component\HttpFoundation\Response;
 
 /**
@@ -50,4 +53,17 @@ public function test8() {
     return new Response('test8');
   }
 
+  public function test9($uid) {
+    $text = 'Route not matched.';
+    try {
+      $match = \Drupal::service('router')->match('/user/' . $uid);
+      if (isset($match['user']) && $match['user'] instanceof UserInterface) {
+        $text = sprintf('User route "%s" was matched.', $match[RouteObjectInterface::ROUTE_NAME]);
+      }
+    }
+    catch (ParamNotConvertedException $e) {
+    }
+    return new Response($text);
+  }
+
 }
diff --git a/core/modules/system/tests/modules/router_test_directory/router_test.routing.yml b/core/modules/system/tests/modules/router_test_directory/router_test.routing.yml
index 7ad0607..d0460a1 100644
--- a/core/modules/system/tests/modules/router_test_directory/router_test.routing.yml
+++ b/core/modules/system/tests/modules/router_test_directory/router_test.routing.yml
@@ -86,3 +86,10 @@ router_test.13:
   defaults:
     _content: '\Drupal\router_test\TestContent::testAccount'
 
+router_test.14:
+  path: '/router_test/test14/{uid}'
+  requirements:
+    _access: 'TRUE'
+  defaults:
+    _controller: '\Drupal\router_test\TestControllers::test9'
+
diff --git a/core/tests/Drupal/Tests/Core/Access/AccessManagerTest.php b/core/tests/Drupal/Tests/Core/Access/AccessManagerTest.php
index 0d13959..b1e041f 100644
--- a/core/tests/Drupal/Tests/Core/Access/AccessManagerTest.php
+++ b/core/tests/Drupal/Tests/Core/Access/AccessManagerTest.php
@@ -63,11 +63,11 @@ class AccessManagerTest extends UnitTestCase {
   protected $urlGenerator;
 
   /**
-   * The parameter converter.
+   * The route enhancer.
    *
-   * @var \PHPUnit_Framework_MockObject_MockObject
+   * @var \Symfony\Cmf\Component\Routing\Enhancer\RouteEnhancerInterface|\PHPUnit_Framework_MockObject_MockObject
    */
-  protected $paramConverter;
+  protected $routeEnhancer;
 
   /**
    * The mocked account.
@@ -119,11 +119,11 @@ protected function setUp() {
       ->method('generate')
       ->will($this->returnValueMap($map));
 
-    $this->paramConverter = $this->getMock('\Drupal\Core\ParamConverter\ParamConverterManager');
+    $this->routeEnhancer = $this->getMock('Symfony\Cmf\Component\Routing\Enhancer\RouteEnhancerInterface');
 
     $this->account = $this->getMock('Drupal\Core\Session\AccountInterface');
 
-    $this->accessManager = new AccessManager($this->routeProvider, $this->urlGenerator, $this->paramConverter, $this->account);
+    $this->accessManager = new AccessManager($this->routeProvider, $this->urlGenerator, $this->routeEnhancer, $this->account);
     $this->accessManager->setContainer($this->container);
   }
 
@@ -152,7 +152,7 @@ public function testSetChecks() {
    */
   public function testSetChecksWithDynamicAccessChecker() {
     // Setup the access manager.
-    $this->accessManager = new AccessManager($this->routeProvider, $this->urlGenerator, $this->paramConverter, $this->account);
+    $this->accessManager = new AccessManager($this->routeProvider, $this->urlGenerator, $this->routeEnhancer, $this->account);
     $this->accessManager->setContainer($this->container);
 
     // Setup the dynamic access checker.
@@ -394,11 +394,11 @@ public function testCheckNamedRoute() {
     // Tests the access with routes without given request.
     $this->accessManager->setRequest(new Request());
 
-    $this->paramConverter->expects($this->at(0))
+    $this->routeEnhancer->expects($this->at(0))
       ->method('enhance')
       ->will($this->returnValue(array()));
 
-    $this->paramConverter->expects($this->at(1))
+    $this->routeEnhancer->expects($this->at(1))
       ->method('enhance')
       ->will($this->returnValue(array()));
 
@@ -431,8 +431,8 @@ public function testCheckNamedRouteWithUpcastedValues() {
       ->method('generate')
       ->will($this->returnValueMap($map));
 
-    $this->paramConverter = $this->getMock('\Drupal\Core\ParamConverter\ParamConverterManager');
-    $this->paramConverter->expects($this->at(0))
+    $this->routeEnhancer = $this->getMock('Symfony\Cmf\Component\Routing\Enhancer\RouteEnhancerInterface');
+    $this->routeEnhancer->expects($this->at(0))
       ->method('enhance')
       ->will($this->returnValue(array('value' => 'upcasted_value')));
 
@@ -444,7 +444,7 @@ public function testCheckNamedRouteWithUpcastedValues() {
       ->with('/test-route-1/example')
       ->will($this->returnValue($subrequest));
 
-    $this->accessManager = new AccessManager($this->routeProvider, $this->urlGenerator, $this->paramConverter, $this->account);
+    $this->accessManager = new AccessManager($this->routeProvider, $this->urlGenerator, $this->routeEnhancer, $this->account);
     $this->accessManager->setContainer($this->container);
     $this->accessManager->setRequest(new Request());
 
@@ -491,8 +491,8 @@ public function testCheckNamedRouteWithDefaultValue() {
       ->with('test_route_1', array('value' => 'example'))
       ->will($this->returnValueMap($map));
 
-    $this->paramConverter = $this->getMock('\Drupal\Core\ParamConverter\ParamConverterManager');
-    $this->paramConverter->expects($this->at(0))
+    $this->routeEnhancer = $this->getMock('Symfony\Cmf\Component\Routing\Enhancer\RouteEnhancerInterface');
+    $this->routeEnhancer->expects($this->at(0))
       ->method('enhance')
       ->with(array('value' => 'example', RouteObjectInterface::ROUTE_OBJECT => $route))
       ->will($this->returnValue(array('value' => 'upcasted_value')));
@@ -504,7 +504,7 @@ public function testCheckNamedRouteWithDefaultValue() {
       ->with('/test-route-1/example')
       ->will($this->returnValue($subrequest));
 
-    $this->accessManager = new AccessManager($this->routeProvider, $this->urlGenerator, $this->paramConverter, $this->account);
+    $this->accessManager = new AccessManager($this->routeProvider, $this->urlGenerator, $this->routeEnhancer, $this->account);
     $this->accessManager->setContainer($this->container);
     $this->accessManager->setRequest(new Request());
 
@@ -578,7 +578,7 @@ public function testCheckException($return_value, $access_mode) {
       ->will($this->returnValue($return_value));
     $container->set('test_incorrect_value', $access_check);
 
-    $access_manager = new AccessManager($route_provider, $this->urlGenerator, $this->paramConverter);
+    $access_manager = new AccessManager($route_provider, $this->urlGenerator, $this->routeEnhancer);
     $access_manager->setContainer($container);
     $access_manager->addCheckService('test_incorrect_value');
 
@@ -633,7 +633,7 @@ protected static function convertAccessCheckInterfaceToString($constant) {
    * Adds a default access check service to the container and the access manager.
    */
   protected function setupAccessChecker() {
-    $this->accessManager = new AccessManager($this->routeProvider, $this->urlGenerator, $this->paramConverter, $this->account);
+    $this->accessManager = new AccessManager($this->routeProvider, $this->urlGenerator, $this->routeEnhancer, $this->account);
     $this->accessManager->setContainer($this->container);
     $access_check = new DefaultAccessCheck();
     $this->container->register('test_access_default', $access_check);
diff --git a/core/tests/Drupal/Tests/Core/Enhancer/ParamConversionEnhancerTest.php b/core/tests/Drupal/Tests/Core/Enhancer/ParamConversionEnhancerTest.php
new file mode 100644
index 0000000..42ced7d
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/Enhancer/ParamConversionEnhancerTest.php
@@ -0,0 +1,149 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\Core\Enhancer\ParamConversionEnhancerTest.
+ */
+
+namespace Drupal\Tests\Core\Enhancer;
+
+use Drupal\Core\Routing\Enhancer\ParamConversionEnhancer;
+use Drupal\Tests\UnitTestCase;
+use Symfony\Cmf\Component\Routing\RouteObjectInterface;
+use Symfony\Component\HttpFoundation\ParameterBag;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\Routing\Route;
+
+/**
+ * Tests the parameter conversion enhancer.
+ *
+ * @coversDefaultClass \Drupal\Core\Routing\Enhancer\ParamConversionEnhancer
+ */
+class ParamConversionEnhancerTest extends UnitTestCase {
+
+  /**
+   * @var \Drupal\Core\Routing\Enhancer\ParamConversionEnhancer
+   */
+  protected $paramConversionEnhancer;
+
+  /**
+   * @var \Drupal\Core\ParamConverter\ParamConverterManager|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $paramConverterManager;
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Parameter conversion enhancer',
+      'description' => 'Tests the parameter conversion enhancer.',
+      'group' => 'Routing',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    $this->paramConverterManager = $this->getMockBuilder('Drupal\Core\ParamConverter\ParamConverterManager')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $this->paramConversionEnhancer = new ParamConversionEnhancer($this->paramConverterManager);
+  }
+
+  /**
+   * @covers ::enhance()
+   */
+  public function testEnhance() {
+    $route = new Route('/test/{id}/{literal}/{null}');
+    $parameters = array(
+      'id' => array(
+        'converter' => 'test_convert',
+      ),
+      'literal' => array(),
+      'null' => array(),
+    );
+    $route->setOption('parameters', $parameters);
+
+    $raw_variables = array(
+      'id' => 1,
+      'literal' => 'this is a literal',
+      'null' => NULL,
+    );
+    $defaults = array(
+      RouteObjectInterface::ROUTE_OBJECT => $route,
+    ) + $raw_variables;
+
+    $expected = $defaults;
+    $expected['id'] = 'something_better!';
+    $expected['_raw_variables'] = new ParameterBag($raw_variables);
+
+    $converter = $this->getMock('Drupal\Core\ParamConverter\ParamConverterInterface');
+    $converter->expects($this->any())
+      ->method('convert')
+      ->with(1, $this->isType('array'), 'id', $this->isType('array'), $this->isInstanceOf('Symfony\Component\HttpFoundation\Request'))
+      ->will($this->returnValue('something_better!'));
+    $this->paramConverterManager->expects($this->any())
+      ->method('getConverter')
+      ->with('test_convert')
+      ->will($this->returnValue($converter));
+
+    $result = $this->paramConversionEnhancer->enhance($defaults, new Request());
+
+    $this->assertEquals($expected, $result);
+  }
+
+  /**
+   * @covers ::enhance()
+   */
+  public function testEnhanceNoConverting() {
+    $route = new Route('/test');
+    $defaults = array(
+      RouteObjectInterface::ROUTE_OBJECT => $route,
+    );
+
+    $expected = $defaults;
+    $expected['_raw_variables'] = new ParameterBag();
+
+    $result = $this->paramConversionEnhancer->enhance($defaults, new Request());
+    $this->assertEquals($expected, $result);
+  }
+
+  /**
+   * @covers ::enhance()
+   *
+   * @expectedException \Drupal\Core\ParamConverter\ParamNotConvertedException
+   */
+  public function testEnhanceMissingParam() {
+    $route = new Route('/test/{id}');
+    $parameters = array(
+      'id' => array(
+        'converter' => 'test_convert',
+      ),
+    );
+    $route->setOption('parameters', $parameters);
+
+    $raw_variables = array(
+      'id' => 1,
+    );
+    $defaults = array(
+      RouteObjectInterface::ROUTE_OBJECT => $route,
+    ) + $raw_variables;
+
+    $converter = $this->getMock('Drupal\Core\ParamConverter\ParamConverterInterface');
+    $converter->expects($this->any())
+      ->method('convert')
+      ->with(1, $this->isType('array'), 'id', $this->isType('array'), $this->isInstanceOf('Symfony\Component\HttpFoundation\Request'))
+      ->will($this->returnValue(NULL));
+    $this->paramConverterManager->expects($this->any())
+      ->method('getConverter')
+      ->with('test_convert')
+      ->will($this->returnValue($converter));
+
+    $this->paramConversionEnhancer->enhance($defaults, new Request());
+  }
+
+}
diff --git a/core/tests/Drupal/Tests/Core/ParamConverter/ParamConverterManagerTest.php b/core/tests/Drupal/Tests/Core/ParamConverter/ParamConverterManagerTest.php
index 71671a0..42ffeca 100644
--- a/core/tests/Drupal/Tests/Core/ParamConverter/ParamConverterManagerTest.php
+++ b/core/tests/Drupal/Tests/Core/ParamConverter/ParamConverterManagerTest.php
@@ -9,16 +9,29 @@
 
 use Drupal\Core\ParamConverter\ParamConverterManager;
 use Drupal\Tests\UnitTestCase;
-use Symfony\Cmf\Component\Routing\RouteObjectInterface;
-use Symfony\Component\DependencyInjection\ContainerBuilder;
-use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\Routing\Route;
+use Symfony\Component\Routing\RouteCollection;
 
 /**
  * Tests the typed data resolver manager.
+ *
+ * @coversDefaultClass \Drupal\Core\ParamConverter\ParamConverterManager
  */
 class ParamConverterManagerTest extends UnitTestCase {
 
+  /**
+   * @var \Symfony\Component\DependencyInjection\ContainerBuilder|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $container;
+
+  /**
+   * @var \Drupal\Core\ParamConverter\ParamConverterManager
+   */
+  protected $manager;
+
+  /**
+   * {@inheritdoc}
+   */
   public static function getInfo() {
     return array(
       'name' => 'Parameter converter manager',
@@ -27,10 +40,13 @@ public static function getInfo() {
     );
   }
 
+  /**
+   * {@inheritdoc}
+   */
   public function setUp() {
     parent::setUp();
 
-    $this->container = new ContainerBuilder();
+    $this->container = $this->getMock('Drupal\Core\DependencyInjection\Container');
     $this->manager = new ParamConverterManager();
     $this->manager->setContainer($this->container);
   }
@@ -40,7 +56,8 @@ public function setUp() {
    *
    * @dataProvider providerTestAddConverter
    *
-   * @see ParamConverterManagerTest::providerTestAddConverter().
+   * @covers ::addConverter()
+   * @covers ::getConverterIds()
    */
   public function testAddConverter($unsorted, $sorted) {
     foreach ($unsorted as $data) {
@@ -59,7 +76,7 @@ public function testAddConverter($unsorted, $sorted) {
    *
    * @dataProvider providerTestGetConverter
    *
-   * @see ParamConverterManagerTest::providerTestGetConverter().
+   * @covers ::getConverter()
    */
   public function testGetConverter($name, $priority, $class) {
     $converter = $this->getMockBuilder('Drupal\Core\ParamConverter\ParamConverterInterface')
@@ -67,15 +84,22 @@ public function testGetConverter($name, $priority, $class) {
       ->getMock();
 
     $this->manager->addConverter($name, $priority);
-    $this->container->set($name, $converter);
+    $this->container->expects($this->once())
+      ->method('get')
+      ->with($name)
+      ->will($this->returnValue($converter));
 
     $this->assertInstanceOf($class, $this->manager->getConverter($name));
+    // Assert that a second call to getConverter() does not use the container.
+    $this->assertInstanceOf($class, $this->manager->getConverter($name));
   }
 
   /**
    * Tests \Drupal\Core\ParamConverter\ParamConverterManager::getConverter().
    *
-   * @expectedException InvalidArgumentException
+   * @covers ::getConverter()
+   *
+   * @expectedException \InvalidArgumentException
    */
   public function testGetConverterException() {
     $this->manager->getConverter('undefined.converter');
@@ -146,48 +170,50 @@ public function providerTestGetConverter() {
   }
 
   /**
-   * Tests the enhance method.
+   * @covers ::setRouteParameterConverters()
    *
-   * @see \Drupal\Core\ParamConverter\ParamConverterManager::enhance().
+   * @dataProvider providerTestSetRouteParameterConverters
    */
-  public function testEnhance() {
-    // Create a mock route using a mock parameter converter.
+  public function testSetRouteParameterConverters($path, $parameters = NULL, $expected = NULL) {
     $converter = $this->getMock('Drupal\Core\ParamConverter\ParamConverterInterface');
-    $this->manager->addConverter('test_convert');
+    $converter->expects($this->any())
+      ->method('applies')
+      ->with($this->anything(), 'id', $this->anything())
+      ->will($this->returnValue(TRUE));
+    $this->manager->addConverter('applied');
+    $this->container->expects($this->any())
+      ->method('get')
+      ->with('applied')
+      ->will($this->returnValue($converter));
 
-    $this->container->set('test_convert', $converter);
+    $route = new Route($path);
+    if ($parameters) {
+      $route->setOption('parameters', $parameters);
+    }
+    $collection = new RouteCollection();
+    $collection->add('test_route', $route);
 
-    $route = new Route('/test/{id}');
-    $parameters = array();
-    $parameters['id'] = array(
-      'converter' => 'test_convert'
+    $this->manager->setRouteParameterConverters($collection);
+    foreach ($collection as $route) {
+      $result = $route->getOption('parameters');
+      if ($expected) {
+        $this->assertSame($expected, $result['id']['converter']);
+      }
+      else {
+        $this->assertNull($result);
+      }
+    }
+  }
+
+  /**
+   * Provides data for testSetRouteParameterConverters().
+   */
+  public function providerTestSetRouteParameterConverters() {
+    return array(
+      array('/test'),
+      array('/test/{id}', array('id' => array()), 'applied'),
+      array('/test/{id}', array('id' => array('converter' => 'predefined')), 'predefined'),
     );
-    $route->setOption('parameters', $parameters);
-
-    $defaults = array();
-    $defaults[RouteObjectInterface::ROUTE_OBJECT] = $route;
-    $defaults['id'] = 1;
-    $defaults['_entity'] = &$defaults['id'];
-
-    $request = new Request();
-
-    $entity = $this->getMockBuilder('\Drupal\user\Entity\User')
-      ->disableOriginalConstructor()
-      ->getMock();
-
-    $converter->expects($this->once())
-      ->method('convert')
-      ->with($this->equalTo(1))
-      ->will($this->returnValue($entity));
-
-    $defaults = $this->manager->enhance($defaults, $request);
-
-    // The value of 1 should be upcast to the User object for UID 1.
-    $this->assertSame($entity, $defaults['id']);
-    // The parameter for the user ID should be stored in the raw variables.
-    $this->assertTrue($defaults['_raw_variables']->has('id'));
-    // The raw non-upcasted value for the user should be the UID.
-    $this->assertEquals(1, $defaults['_raw_variables']->get('id'));
   }
 
 }
