diff --git a/core/lib/Drupal/Core/CoreBundle.php b/core/lib/Drupal/Core/CoreBundle.php
index 624c716..f043ddb 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;
@@ -195,6 +197,15 @@ 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', array('priority' => 0));
+    $container->register('paramconverter.entity_explicit', 'Drupal\Core\ParamConverter\ExplicitEntityConverter')
+      ->addArgument(new Reference('plugin.manager.entity'))
+      ->addTag('paramconverter', array('priority' => 10));
+    $container->register('paramconverter.entity', 'Drupal\Core\ParamConverter\EntityConverter')
+      ->addArgument(new Reference('plugin.manager.entity'))
+      ->addTag('paramconverter', array('priority' => 0));
+
     $container->register('router_processor_subscriber', 'Drupal\Core\EventSubscriber\RouteProcessorSubscriber')
       ->addTag('event_subscriber');
     $container->register('router_listener', 'Symfony\Component\HttpKernel\EventListener\RouterListener')
@@ -271,6 +282,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..32ff70a
--- /dev/null
+++ b/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterParamConvertersPass.php
@@ -0,0 +1,47 @@
+<?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 = $attributes[0]['priority'] ? $attributes[0]['priority'] : 0;
+
+      $services[$priority][] = new Reference($id);
+    }
+
+    krsort($services);
+
+    foreach($services as $bucket) {
+      foreach($bucket as $service) {
+        $manager->addMethodCall('addConverterService', 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..8c99e99
--- /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 = $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..a6a6888
--- /dev/null
+++ b/core/lib/Drupal/Core/ParamConverter/EntityConverter.php
@@ -0,0 +1,68 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\Core\ParamConverter\EntityConverter.
+ */
+
+namespace Drupal\Core\ParamConverter;
+
+use Symfony\Cmf\Component\Routing\RouteObjectInterface;
+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 $entity_manager;
+
+  /**
+   * Constructs a new EntityAliasConverter.
+   *
+   * @param \Drupal\Core\Entity\EntityManager $entity_manager
+   */
+  public function __construct(EntityManager $entity_manager) {
+    $this->entity_manager = $entity_manager;
+  }
+
+  /**
+   * Tries to upcast every variable to a entity type of the same name.
+   *
+   * If there is no entity type with the name of the variable it simply skips it.
+   * It will not process variables which are marked as converted. It will mark
+   * any variable it processes as converted.
+   *
+   * @param array $defaults
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   *   The current request.
+   *
+   * @return array The modified defaults.
+   */
+  public function process($defaults, $request) {
+    $variables = $defaults[RouteObjectInterface::ROUTE_OBJECT]->compile()->getVariables();
+
+    $types = array_keys(entity_get_info());
+
+    foreach ($variables as $var) {
+      // Only upcast if there is a type with the name of the variable
+      // and the variable hasn't been upcast yet.
+      if (in_array($var, $types) && ! in_array($var, $defaults['_converted'])) {
+        $value = $defaults[$var];
+
+        $entities = $this->entity_manager->getStorageController($var)->load(array($value));
+
+        // Make sure $entities is null, if upcasting fails.
+        $entity = $entities ? reset($entities) : null;
+        $defaults[$var] = $entity;
+        $defaults['_converted'][] = $var;
+      }
+    }
+    return $defaults;
+  }
+}
diff --git a/core/lib/Drupal/Core/ParamConverter/ExplicitEntityConverter.php b/core/lib/Drupal/Core/ParamConverter/ExplicitEntityConverter.php
new file mode 100644
index 0000000..b0061b2
--- /dev/null
+++ b/core/lib/Drupal/Core/ParamConverter/ExplicitEntityConverter.php
@@ -0,0 +1,95 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\Core\ParamConverter\ExplicitEntityConverter.
+ */
+
+namespace Drupal\Core\ParamConverter;
+
+use Symfony\Cmf\Component\Routing\RouteObjectInterface;
+use Drupal\Core\Entity\EntityManager;
+
+/**
+ * Allows the upcasting of entity ids to an entity type defined in
+ * the route options.
+ */
+class ExplicitEntityConverter implements ParamConverterInterface {
+
+  /**
+   * Entity manager which perform the upcasting in the end.
+   *
+   * @var \Drupal\Core\Entity\EntityManager
+   */
+  protected $entity_manager;
+
+  /**
+   * Constructs a new ExplicitEntityConverter.
+   *
+   * @param \Drupal\Core\Entity\EntityManager $entity_manager
+   */
+  public function __construct(EntityManager $entity_manager) {
+    $this->entity_manager = $entity_manager;
+  }
+
+  /**
+   * Upcasts every variable with a converter option defined in the
+   * route definition.
+   *
+   * If there is no option with the name of the variable it simply skips it.
+   *
+   * Example:
+   *
+   * pattern: '/some/{var}'
+   * options:
+   *   converters:
+   *    var: 'node'
+   *
+   * This will convert the node id given in $defaults['var'] to a entity of
+   * type node.
+   *
+   * It will not process variables which are marked as converted. It will mark
+   * any variable it processes as converted.
+   *
+   * @param array $defaults
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   *   The current request.
+   *
+   * @return array The modified defaults.
+   */
+  public function process($defaults, $request) {
+    $variables = $defaults[RouteObjectInterface::ROUTE_OBJECT]->compile()->getVariables();
+    $options = $defaults[RouteObjectInterface::ROUTE_OBJECT]->getOptions();
+
+    // Early exit because there are no converters defined in the route options.
+    if (! isset($options['converters'])) {
+      return $defaults;
+    }
+    $converters = $options['converters'];
+
+    $types = array_keys(entity_get_info());
+
+    foreach ($variables as $var) {
+
+      if (array_key_exists($var, $converters)) {
+        $dealiased_var = $converters[$var];
+      } else {
+        continue;
+      }
+
+      // Only upcast if there is a type with the name of the dealiased variable
+      // and the variable hasn't been upcast yet.
+      if (in_array($dealiased_var, $types) && ! in_array($var, $defaults['_converted'])) {
+        $value = $defaults[$var];
+
+        $entities = $this->entity_manager->getStorageController($dealiased_var)->load(array($value));
+
+        // Make sure $entities is null, if upcasting fails.
+        $entity = $entities ? reset($entities) : null;
+        $defaults[$var] = $entity;
+        $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..75543d3
--- /dev/null
+++ b/core/lib/Drupal/Core/ParamConverter/ParamConverterInterface.php
@@ -0,0 +1,24 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\Core\ParamConverter\ParamConverterInterface.
+ */
+
+namespace Drupal\Core\ParamConverter;
+
+/**
+ * Interface for parameter converters.
+ */
+interface ParamConverterInterface {
+
+  /**
+   * Allows to alter the defaults of the current request.
+   *
+   * @param array $defaults
+   *
+   * @return array The modified defaults. Each enhancer MUST return the
+   *   $defaults but may add, remove or alter values.
+   */
+  public function process($defaults, $request);
+}
diff --git a/core/lib/Drupal/Core/ParamConverter/ParamConverterManager.php b/core/lib/Drupal/Core/ParamConverter/ParamConverterManager.php
new file mode 100644
index 0000000..08c58d9
--- /dev/null
+++ b/core/lib/Drupal/Core/ParamConverter/ParamConverterManager.php
@@ -0,0 +1,77 @@
+<?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\Component\HttpKernel\Exception\NotFoundHttpException;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * 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 object.
+ *
+ * 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;
+
+  /**
+   * Adds services to the paramconverter service.
+   *
+   * @see \Drupal\Core\DependencyInjection\Compiler\RegisterParamConvertersPass
+   *
+   * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container
+   *   The container to process.
+   */
+  public function addConverterService($service) {
+    $this->converters[] = $service;
+    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 all the converter had
+    //     a go. See below.
+    $defaults['_converted'] = array();
+
+    foreach ($this->converters as $converter) {
+      $defaults = $converter->process($defaults, $request);
+    }
+
+    // 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..60c62d7
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/Tests/ParamConverter/UpcastingTest.php
@@ -0,0 +1,99 @@
+<?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 {
+
+  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..45389d4
--- /dev/null
+++ b/core/modules/system/tests/modules/paramconverter_test/lib/Drupal/paramconverter_test/TestControllers.php
@@ -0,0 +1,24 @@
+<?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 test_user_node_foo($user, $node, $foo) {
+    return "user: " . (is_object($user) ? $user->label() : $user)
+       . ", node: " . (is_object($node) ? $node->label() : $node)
+        . ", foo: " . (is_object($foo)  ? $foo->label()  : $foo);
+  }
+
+  public function test_node_set_parent(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..92fc995
--- /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..442e3a1
--- /dev/null
+++ b/core/modules/system/tests/modules/paramconverter_test/paramconverter_test.routing.yml
@@ -0,0 +1,38 @@
+paramconverter_test_user_node_foo:
+  pattern: '/paramconverter_test/test_user_node_foo/{user}/{node}/{foo}'
+  defaults:
+    _content: '\Drupal\paramconverter_test\TestControllers::test_user_node_foo'
+  requirements:
+    _access: 'TRUE'
+
+paramconverter_test_node_user_user:
+  pattern: '/paramconverter_test/test_node_user_user/{node}/{foo}/{user}'
+  defaults:
+    _content: '\Drupal\paramconverter_test\TestControllers::test_user_node_foo'
+  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::test_user_node_foo'
+  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::test_node_set_parent'
+  options:
+    converters:
+      parent: 'node'
+
