diff --git a/core/includes/path.inc b/core/includes/path.inc
index d0c954e..120151e 100644
--- a/core/includes/path.inc
+++ b/core/includes/path.inc
@@ -88,7 +88,10 @@ function current_path() {
   // fallback code below, once the path alias logic has been figured out in
   // http://drupal.org/node/1269742.
   if (drupal_container()->isScopeActive('request')) {
-    return drupal_container()->get('request')->attributes->get('system_path');
+    $path = drupal_container()->get('request')->attributes->get('system_path');
+    if ($path !== NULL) {
+      return $path;
+    }
   }
   // If we are outside the request scope, fall back to using the path stored in
   // _current_path().
diff --git a/core/lib/Drupal/Core/CoreBundle.php b/core/lib/Drupal/Core/CoreBundle.php
index 4684695..80b9439 100644
--- a/core/lib/Drupal/Core/CoreBundle.php
+++ b/core/lib/Drupal/Core/CoreBundle.php
@@ -11,7 +11,9 @@
 use Drupal\Core\DependencyInjection\Compiler\RegisterAccessChecksPass;
 use Drupal\Core\DependencyInjection\Compiler\RegisterMatchersPass;
 use Drupal\Core\DependencyInjection\Compiler\RegisterRouteFiltersPass;
+use Drupal\Core\DependencyInjection\Compiler\RegisterRouteEnhancersPass;
 use Drupal\Core\DependencyInjection\Compiler\RegisterSerializationClassesPass;
+use Drupal\Core\DependencyInjection\Compiler\RegisterParamConvertersPass;
 use Symfony\Component\DependencyInjection\ContainerBuilder;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\DependencyInjection\Reference;
@@ -202,6 +204,12 @@ public function build(ContainerBuilder $container) {
     $container->register('mime_type_matcher', 'Drupal\Core\Routing\MimeTypeMatcher')
       ->addTag('route_filter');
 
+    $container->register('paramconverter_manager', 'Drupal\Core\ParamConverter\ParamConverterManager')
+      ->addTag('route_enhancer');
+    $container->register('paramconverter.entity', 'Drupal\Core\ParamConverter\EntityConverter')
+      ->addArgument(new Reference('plugin.manager.entity'))
+      ->addTag('paramconverter');
+
     $container->register('router_processor_subscriber', 'Drupal\Core\EventSubscriber\RouteProcessorSubscriber')
       ->addArgument(new Reference('content_negotiation'))
       ->addTag('event_subscriber');
@@ -279,6 +287,9 @@ public function build(ContainerBuilder $container) {
     // Add a compiler pass for registering event subscribers.
     $container->addCompilerPass(new RegisterKernelListenersPass(), PassConfig::TYPE_AFTER_REMOVING);
     $container->addCompilerPass(new RegisterAccessChecksPass());
+    // Add a compiler pass for upcasting of entity route parameters.
+    $container->addCompilerPass(new RegisterParamConvertersPass());
+    $container->addCompilerPass(new RegisterRouteEnhancersPass());
   }
 
   /**
diff --git a/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterParamConvertersPass.php b/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterParamConvertersPass.php
new file mode 100644
index 0000000..6fe1447
--- /dev/null
+++ b/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterParamConvertersPass.php
@@ -0,0 +1,48 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\Core\DependencyInjection\Compiler\RegisterParamConvertersPass.
+ */
+
+namespace Drupal\Core\DependencyInjection\Compiler;
+
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
+use Symfony\Component\DependencyInjection\Reference;
+
+/**
+ * Registers EntityConverter services with the ParamConverterManager.
+ */
+class RegisterParamConvertersPass implements CompilerPassInterface {
+
+  /**
+   * Adds services tagged with "paramconverter" to the param converter service.
+   *
+   * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container
+   *   The container to process.
+   */
+  public function process(ContainerBuilder $container) {
+
+    if (!$container->hasDefinition('paramconverter_manager')) {
+      return;
+    }
+
+    $manager = $container->getDefinition('paramconverter_manager');
+
+    $services = array();
+    foreach ($container->findTaggedServiceIds('paramconverter') as $id => $attributes) {
+      $priority = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0;
+
+      $services[$priority][] = new Reference($id);
+    }
+
+    krsort($services);
+
+    foreach ($services as $priority) {
+      foreach ($priority as $service) {
+        $manager->addMethodCall('addConverter', array($service));
+      }
+    }
+  }
+}
diff --git a/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterRouteEnhancersPass.php b/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterRouteEnhancersPass.php
new file mode 100644
index 0000000..2718b68
--- /dev/null
+++ b/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterRouteEnhancersPass.php
@@ -0,0 +1,38 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\Core\DependencyInjection\Compiler\RegisterRouteEnhancersPass.
+ */
+
+namespace Drupal\Core\DependencyInjection\Compiler;
+
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
+use Symfony\Component\DependencyInjection\Reference;
+
+/**
+ * Registers route enhancer services with the router.
+ */
+class RegisterRouteEnhancersPass implements CompilerPassInterface {
+
+  /**
+   * Adds services tagged with "route_enhancer" to the router.
+   *
+   * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container
+   *   The container to process.
+   */
+  public function process(ContainerBuilder $container) {
+    if (!$container->hasDefinition('router.dynamic')) {
+      return;
+    }
+
+    $router = $container->getDefinition('router.dynamic');
+
+    $services = array();
+    foreach ($container->findTaggedServiceIds('route_enhancer') as $id => $attributes) {
+      $priority = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0;
+      $router->addMethodCall('addRouteEnhancer', array(new Reference($id), $priority));
+    }
+  }
+}
diff --git a/core/lib/Drupal/Core/ParamConverter/EntityConverter.php b/core/lib/Drupal/Core/ParamConverter/EntityConverter.php
new file mode 100644
index 0000000..3773eb1
--- /dev/null
+++ b/core/lib/Drupal/Core/ParamConverter/EntityConverter.php
@@ -0,0 +1,108 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\Core\ParamConverter\EntityConverter.
+ */
+
+namespace Drupal\Core\ParamConverter;
+
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\Routing\Route;
+use Drupal\Core\Entity\EntityManager;
+
+/**
+ * This class allows the upcasting of entity ids to the respective entity
+ * object.
+ */
+class EntityConverter implements ParamConverterInterface {
+  /**
+   * Entity manager which perform the upcasting in the end.
+   *
+   * @var \Drupal\Core\Entity\EntityManager
+   */
+  protected $entityManager;
+
+  /**
+   * Constructs a new EntityConverter.
+   *
+   * @param \Drupal\Core\Entity\EntityManager $entityManager
+   *   The entity manager.
+   */
+  public function __construct(EntityManager $entityManager) {
+    $this->entityManager = $entityManager;
+  }
+
+  /**
+   * Tries to upcast every variable to an entity type.
+   *
+   * If there is a type denoted in the route options it will try to upcast to
+   * it, if there is no definition in the options it will try to upcast to an
+   * entity type of that name. If the chosen enity type does not exists it will
+   * leave the variable untouched.
+   * If the entity type exist, but there is no entity with the given id it will
+   * convert the variable to NULL.
+   *
+   * Example:
+   *
+   * pattern: '/a/{user}/some/{foo}/and/{bar}/'
+   * options:
+   *   converters:
+   *     foo: 'node'
+   *
+   * The value for {user} will be converted to a user entity and the value
+   * for {foo} to a node entity, but it will not touch the value for {bar}.
+   *
+   * It will not process variables which are marked as converted. It will mark
+   * any variable it processes as converted.
+   *
+   * @param array $defaults
+   *   The merge of the default values from the route and the values provided
+   *   by the path via placeholders.
+   * @param \Symfony\Component\Routing\Route $route
+   *   The route object.
+   *
+   * @return array
+   *   The modified defaults.
+   */
+  public function process(array $defaults, Route $route) {
+    $variables = $route->compile()->getVariables();
+
+    $options = $route->getOptions();
+    $configuredTypes = isset($options['converters']) ? $options['converters'] : array();
+
+    $entityTypes = array_keys($this->entityManager->getDefinitions());
+
+    foreach ($variables as $var) {
+      // Do not process this variable if it's already marked as converted.
+      if (in_array($var, $defaults['_converted'])) {
+        continue;
+      }
+
+      // Obtain entity type to convert to from the route configuration or just
+      // use the variable name as default.
+      if (array_key_exists($var, $configuredTypes)) {
+        $type = $configuredTypes[$var];
+      }
+      else {
+        $type = $var;
+      }
+
+      if (in_array($type, $entityTypes)) {
+        $value = $defaults[$var];
+
+        $storageController = $this->entityManager->getStorageController($type);
+        $entities = $storageController->load(array($value));
+
+        // Make sure $entities is null, if upcasting fails.
+        $entity = $entities ? reset($entities) : NULL;
+        $defaults[$var] = $entity;
+
+        // Mark this variable as converted.
+        $defaults['_converted'][] = $var;
+      }
+    }
+
+    return $defaults;
+  }
+}
diff --git a/core/lib/Drupal/Core/ParamConverter/ParamConverterInterface.php b/core/lib/Drupal/Core/ParamConverter/ParamConverterInterface.php
new file mode 100644
index 0000000..b49a75c
--- /dev/null
+++ b/core/lib/Drupal/Core/ParamConverter/ParamConverterInterface.php
@@ -0,0 +1,31 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\Core\ParamConverter\ParamConverterInterface.
+ */
+
+namespace Drupal\Core\ParamConverter;
+
+use Symfony\Component\Routing\Route;
+
+/**
+ * Interface for parameter converters.
+ */
+interface ParamConverterInterface {
+
+  /**
+   * Allows to alter the defaults of the current request.
+   *
+   * @param array $defaults 
+   *   The merge of the default values from the route and
+   *   the values provided by the path via placeholders.
+   * @param \Symfony\Component\Routing\Route $route
+   *   The route object.
+   *
+   * @return array 
+   *   The modified defaults. Each enhancer MUST return the $defaults but may 
+   *   add, remove or alter values.
+   */
+  public function process(array $defaults, Route $route);
+}
diff --git a/core/lib/Drupal/Core/ParamConverter/ParamConverterManager.php b/core/lib/Drupal/Core/ParamConverter/ParamConverterManager.php
new file mode 100644
index 0000000..8fc78f7
--- /dev/null
+++ b/core/lib/Drupal/Core/ParamConverter/ParamConverterManager.php
@@ -0,0 +1,84 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\Core\ParamConverter\ParamConverterManager.
+ */
+
+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\HttpKernel\Exception\NotFoundHttpException;
+use Symfony\Component\HttpFoundation\Request;
+
+use Drupal\Core\ParamConverter\ParamConverterInterface;
+
+/**
+ * Provides a service which allows to enhance (say alter) the arguments coming
+ * from the URL.
+ *
+ * A typical use case for this would be upcasting a node id to a node entity.
+ *
+ * This class will not enhance any of the arguments itself, but allow other
+ * services to register to do so.
+ */
+class ParamConverterManager implements RouteEnhancerInterface {
+
+  protected $converters;
+
+  /**
+   * Add a converter to the paramconverter service.
+   *
+   * @see \Drupal\Core\DependencyInjection\Compiler\RegisterParamConvertersPass
+   *
+   * @param \Drupal\Core\ParamConverter\ParamConverterInterface $converter
+   *   The converter to add.
+   */
+  public function addConverter(ParamConverterInterface $converter) {
+    $this->converters[] = $converter;
+    return $this;
+  }
+
+  /**
+   * Implements \Symfony\Cmf\Component\Routing\Enhancer\ŖouteEnhancerIterface.
+   *
+   * Iterates over all registered converters and allows them to alter the
+   * defaults.
+   *
+   * @param array $defaults 
+   *   The getRouteDefaults array.
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   *   The current request.
+   *
+   * @return array 
+   *   The modified defaults.
+   */
+  public function enhance(array $defaults, Request $request) {
+    // This array will collect the names of all variables which have been
+    // altered by a converter.
+    // This serves two purposes:
+    // 1. It might prevent converters later in the pipeline to process
+    //    a variable again.
+    // 2. To check if upcasting was successfull after each converter had
+    //    a go. See below.
+    $defaults['_converted'] = array();
+
+    $route = $defaults[RouteObjectInterface::ROUTE_OBJECT];
+
+    foreach ($this->converters as $converter) {
+      $defaults = $converter->process($defaults, $route);
+    }
+
+    // Check if all upcasting yielded a result.
+    // If an upcast value is NULL do a 404.
+    foreach ($defaults['_converted'] as $variable) {
+      if ($defaults[$variable] === NULL) {
+        throw new NotFoundHttpException();
+      }
+    }
+
+    return $defaults;
+  }
+}
diff --git a/core/modules/system/lib/Drupal/system/Tests/ParamConverter/UpcastingTest.php b/core/modules/system/lib/Drupal/system/Tests/ParamConverter/UpcastingTest.php
new file mode 100644
index 0000000..14a0422
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/Tests/ParamConverter/UpcastingTest.php
@@ -0,0 +1,77 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\system\Tests\ParamConverter\UpcastingTest.
+ */
+
+namespace Drupal\system\Tests\ParamConverter;
+
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
+use Drupal\Core\DependencyInjection\ContainerBuilder;
+use Drupal\simpletest\WebTestBase;
+
+/**
+ * Web tests for the upcasting.
+ */
+class UpcastingTest extends WebTestBase {
+
+  /**
+   * Implement getInfo().
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Upcasting tests',
+      'description' => 'Tests upcasting of url arguments to entities.',
+      'group' => 'ParamConverter',
+    );
+  }
+
+  public static $modules = array('paramconverter_test');
+
+  /**
+   * Confirms that all parameters are converted as expected.
+   *
+   * All of these requests end up being proccessed by a controller with this
+   * the signature: f($user, $node, $foo) returning either values or labels
+   * like "user: Dries, node: First post, foo: bar"
+   *
+   * The tests shuffle the parameters around an checks if the right thing is
+   * happening.
+   */
+  public function testUpcasting() {
+    $node = $this->drupalCreateNode(array('title' => $this->randomName(8)));
+    $user = $this->drupalCreateUser(array('access content'));
+    $foo = 'bar';
+
+    // paramconverter_test/test_user_node_foo/{user}/{node}/{foo}
+    $this->drupalGet("paramconverter_test/test_user_node_foo/{$user->uid}/{$node->nid}/$foo");
+    $this->assertRaw("user: {$user->label()}, node: {$node->label()}, foo: $foo", 'user and node upcast by entity name');
+
+    // paramconverter_test/test_node_user_user/{node}/{foo}/{user}
+    // converters:
+    //   foo: 'user'
+    $this->drupalGet("paramconverter_test/test_node_user_user/{$node->nid}/{$user->uid}/{$user->uid}");
+    $this->assertRaw("user: {$user->label()}, node: {$node->label()}, foo: {$user->label()}", 'foo converted to user as well');
+
+    // paramconverter_test/test_node_node_foo/{user}/{node}/{foo}
+    // converters:
+    //   user: 'node'
+    $this->drupalGet("paramconverter_test/test_node_node_foo/{$node->nid}/{$node->nid}/$foo");
+    $this->assertRaw("user: {$node->label()}, node: {$node->label()}, foo: $foo", 'user is upcast to node (rather than to user)');
+  }
+
+  /**
+   * Confirms we can upcast to controller arguments of the same type.
+   */
+  public function testSameTypes() {
+    $node = $this->drupalCreateNode(array('title' => $this->randomName(8)));
+    $parent = $this->drupalCreateNode(array('title' => $this->randomName(8)));
+    // paramconverter_test/node/{node}/set/parent/{parent}
+    // converters:
+    //   parent: 'node'
+    $this->drupalGet("paramconverter_test/node/" . $node->nid . "/set/parent/" . $parent->nid);
+    $this->assertRaw("Setting '" . $parent->title . "' as parent of '" . $node->title . "'.");
+  }
+}
diff --git a/core/modules/system/tests/modules/paramconverter_test/lib/Drupal/paramconverter_test/TestControllers.php b/core/modules/system/tests/modules/paramconverter_test/lib/Drupal/paramconverter_test/TestControllers.php
new file mode 100644
index 0000000..ddb4833
--- /dev/null
+++ b/core/modules/system/tests/modules/paramconverter_test/lib/Drupal/paramconverter_test/TestControllers.php
@@ -0,0 +1,27 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\paramconverter_test\TestControllers.
+ */
+
+namespace Drupal\paramconverter_test;
+
+use Drupal\node\Plugin\Core\Entity\Node;
+
+/**
+ * Controller routine for testing the paramconverter.
+ */
+class TestControllers {
+
+  public function testUserNodeFoo($user, $node, $foo) {
+    $retval = "user: " . (is_object($user) ? $user->label() : $user);
+    $retval .= ", node: " . (is_object($node) ? $node->label() : $node);
+    $retval .= ", foo: " . (is_object($foo) ? $foo->label() : $foo);
+    return $retval;
+  }
+
+  public function testNodeSetParent(Node $node, Node $parent) {
+    return "Setting '{$parent->title}' as parent of '{$node->title}'.";
+  }
+}
diff --git a/core/modules/system/tests/modules/paramconverter_test/paramconverter_test.info b/core/modules/system/tests/modules/paramconverter_test/paramconverter_test.info
new file mode 100644
index 0000000..3db382a
--- /dev/null
+++ b/core/modules/system/tests/modules/paramconverter_test/paramconverter_test.info
@@ -0,0 +1,6 @@
+name = "ParamConverter test"
+description = "Support module for paramconverter testing."
+package = Testing
+version = VERSION
+core = 8.x
+hidden = TRUE
diff --git a/core/modules/system/tests/modules/paramconverter_test/paramconverter_test.module b/core/modules/system/tests/modules/paramconverter_test/paramconverter_test.module
new file mode 100644
index 0000000..adb7709
--- /dev/null
+++ b/core/modules/system/tests/modules/paramconverter_test/paramconverter_test.module
@@ -0,0 +1,6 @@
+<?php
+
+/**
+ * @file
+ * Intentionally blank file. 
+ */
diff --git a/core/modules/system/tests/modules/paramconverter_test/paramconverter_test.routing.yml b/core/modules/system/tests/modules/paramconverter_test/paramconverter_test.routing.yml
new file mode 100644
index 0000000..9d226e4
--- /dev/null
+++ b/core/modules/system/tests/modules/paramconverter_test/paramconverter_test.routing.yml
@@ -0,0 +1,36 @@
+paramconverter_test_user_node_foo:
+  pattern: '/paramconverter_test/test_user_node_foo/{user}/{node}/{foo}'
+  defaults:
+    _content: '\Drupal\paramconverter_test\TestControllers::testUserNodeFoo'
+  requirements:
+    _access: 'TRUE'
+
+paramconverter_test_node_user_user:
+  pattern: '/paramconverter_test/test_node_user_user/{node}/{foo}/{user}'
+  defaults:
+    _content: '\Drupal\paramconverter_test\TestControllers::testUserNodeFoo'
+  requirements:
+    _access: 'TRUE'
+  options:
+    converters:
+      foo: 'user'
+
+paramconverter_test_node_node_foo:
+  pattern: '/paramconverter_test/test_node_node_foo/{user}/{node}/{foo}'
+  defaults:
+    _content: '\Drupal\paramconverter_test\TestControllers::testUserNodeFoo'
+  requirements:
+    _access: 'TRUE'
+  options:
+    converters:
+      user: 'node'
+
+paramconverter_test_node_set_parent:
+  pattern: '/paramconverter_test/node/{node}/set/parent/{parent}'
+  requirements:
+    _access: 'TRUE'
+  defaults:
+    _content: '\Drupal\paramconverter_test\TestControllers::testNodeSetParent'
+  options:
+    converters:
+      parent: 'node'
