diff --git a/core/lib/Drupal/Core/CoreBundle.php b/core/lib/Drupal/Core/CoreBundle.php
index e1147ac..9a5281f 100644
--- a/core/lib/Drupal/Core/CoreBundle.php
+++ b/core/lib/Drupal/Core/CoreBundle.php
@@ -12,6 +12,7 @@
 use Drupal\Core\DependencyInjection\Compiler\RegisterMatchersPass;
 use Drupal\Core\DependencyInjection\Compiler\RegisterNestedMatchersPass;
 use Drupal\Core\DependencyInjection\Compiler\RegisterSerializationClassesPass;
+use Drupal\Core\DependencyInjection\Compiler\RegisterEntityParamConvertersPass;
 use Symfony\Component\DependencyInjection\ContainerBuilder;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\DependencyInjection\Reference;
@@ -181,6 +182,12 @@ public function build(ContainerBuilder $container) {
     $container->register('first_entry_final_matcher', 'Drupal\Core\Routing\FirstEntryFinalMatcher')
       ->addTag('nested_matcher', array('method' => 'setFinalMatcher'));
 
+    $container->register('paramconverter_manager', 'Drupal\Core\ParamConverter\ParamConverterManager')
+      ->addMethodCall('setContainer', array(new Reference('service_container')));
+    $container->register('paramconverter.subscriber', 'Drupal\Core\EventSubscriber\ParamConverterSubscriber')
+      ->addArgument(new Reference('paramconverter_manager'))
+      ->addTag('event_subscriber');
+
     $container->register('router_processor_subscriber', 'Drupal\Core\EventSubscriber\RouteProcessorSubscriber')
       ->addTag('event_subscriber');
     $container->register('router_listener', 'Symfony\Component\HttpKernel\EventListener\RouterListener')
@@ -245,6 +252,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 RegisterEntityParamConvertersPass());
+
   }
 
 }
diff --git a/core/lib/Drupal/Core/CoreBundle.php.orig b/core/lib/Drupal/Core/CoreBundle.php.orig
new file mode 100644
index 0000000..e1147ac
--- /dev/null
+++ b/core/lib/Drupal/Core/CoreBundle.php.orig
@@ -0,0 +1,250 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\CoreBundle.
+ */
+
+namespace Drupal\Core;
+
+use Drupal\Core\DependencyInjection\Compiler\RegisterKernelListenersPass;
+use Drupal\Core\DependencyInjection\Compiler\RegisterAccessChecksPass;
+use Drupal\Core\DependencyInjection\Compiler\RegisterMatchersPass;
+use Drupal\Core\DependencyInjection\Compiler\RegisterNestedMatchersPass;
+use Drupal\Core\DependencyInjection\Compiler\RegisterSerializationClassesPass;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\DependencyInjection\Reference;
+use Symfony\Component\DependencyInjection\Scope;
+use Symfony\Component\HttpKernel\Bundle\Bundle;
+use Symfony\Component\DependencyInjection\Compiler\PassConfig;
+
+/**
+ * Bundle class for mandatory core services.
+ *
+ * This is where Drupal core registers all of its services to the Dependency
+ * Injection Container. Modules wishing to register services to the container
+ * should extend Symfony's Bundle class directly, not this class.
+ */
+class CoreBundle extends Bundle {
+
+  /**
+   * Implements \Symfony\Component\HttpKernel\Bundle\BundleInterface::build().
+   */
+  public function build(ContainerBuilder $container) {
+
+    // Register active configuration storage.
+    $container
+      ->register('config.cachedstorage.storage', 'Drupal\Core\Config\FileStorage')
+      ->addArgument(config_get_config_directory(CONFIG_ACTIVE_DIRECTORY));
+    // @todo Replace this with a cache.factory service plus 'config' argument.
+    $container
+      ->register('cache.config', 'Drupal\Core\Cache\CacheBackendInterface')
+      ->setFactoryClass('Drupal\Core\Cache\CacheFactory')
+      ->setFactoryMethod('get')
+      ->addArgument('config');
+
+    $container
+      ->register('config.storage', 'Drupal\Core\Config\CachedStorage')
+      ->addArgument(new Reference('config.cachedstorage.storage'))
+      ->addArgument(new Reference('cache.config'));
+
+    // Register configuration object factory.
+    $container->register('config.subscriber.globalconf', 'Drupal\Core\EventSubscriber\ConfigGlobalOverrideSubscriber');
+    $container->register('dispatcher', 'Symfony\Component\EventDispatcher\EventDispatcher')
+      ->addMethodCall('addSubscriber', array(new Reference('config.subscriber.globalconf')));
+    $container->register('config.factory', 'Drupal\Core\Config\ConfigFactory')
+      ->addArgument(new Reference('config.storage'))
+      ->addArgument(new Reference('dispatcher'));
+
+    // Register staging configuration storage.
+    $container
+      ->register('config.storage.staging', 'Drupal\Core\Config\FileStorage')
+      ->addArgument(config_get_config_directory(CONFIG_STAGING_DIRECTORY));
+
+    // Register the service for the default database connection.
+    $container->register('database', 'Drupal\Core\Database\Connection')
+      ->setFactoryClass('Drupal\Core\Database\Database')
+      ->setFactoryMethod('getConnection')
+      ->addArgument('default');
+    // Register the KeyValueStore factory.
+    $container
+      ->register('keyvalue', 'Drupal\Core\KeyValueStore\KeyValueFactory')
+      ->addArgument(new Reference('service_container'));
+    $container
+      ->register('keyvalue.database', 'Drupal\Core\KeyValueStore\KeyValueDatabaseFactory')
+      ->addArgument(new Reference('database'));
+
+    $container->register('path.alias_manager', 'Drupal\Core\Path\AliasManager')
+      ->addArgument(new Reference('database'))
+      ->addArgument(new Reference('keyvalue'));
+
+    $container->register('http_client_simpletest_subscriber', 'Drupal\Core\Http\Plugin\SimpletestHttpRequestSubscriber');
+    $container->register('http_default_client', 'Guzzle\Http\Client')
+      ->addArgument(NULL)
+      ->addArgument(array(
+        'curl.CURLOPT_TIMEOUT' => 30.0,
+        'curl.CURLOPT_MAXREDIRS' => 3,
+      ))
+      ->addMethodCall('addSubscriber', array(new Reference('http_client_simpletest_subscriber')))
+      ->addMethodCall('setUserAgent', array('Drupal (+http://drupal.org/)'));
+
+    // Register the EntityManager.
+    $container->register('plugin.manager.entity', 'Drupal\Core\Entity\EntityManager');
+
+    // The 'request' scope and service enable services to depend on the Request
+    // object and get reconstructed when the request object changes (e.g.,
+    // during a subrequest).
+    $container->addScope(new Scope('request'));
+    $container->register('request', 'Symfony\Component\HttpFoundation\Request')
+      ->setSynthetic(TRUE);
+
+    $container->register('dispatcher', 'Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher')
+      ->addArgument(new Reference('service_container'));
+    $container->register('resolver', 'Drupal\Core\ControllerResolver')
+      ->addArgument(new Reference('service_container'));
+    $container->register('http_kernel', 'Drupal\Core\HttpKernel')
+      ->addArgument(new Reference('dispatcher'))
+      ->addArgument(new Reference('service_container'))
+      ->addArgument(new Reference('resolver'));
+    $container->register('language_manager', 'Drupal\Core\Language\LanguageManager')
+      ->addArgument(new Reference('request'))
+      ->setScope('request');
+    $container->register('database.slave', 'Drupal\Core\Database\Connection')
+      ->setFactoryClass('Drupal\Core\Database\Database')
+      ->setFactoryMethod('getConnection')
+      ->addArgument('slave');
+    $container->register('typed_data', 'Drupal\Core\TypedData\TypedDataManager');
+    // Add the user's storage for temporary, non-cache data.
+    $container->register('lock', 'Drupal\Core\Lock\DatabaseLockBackend');
+    $container->register('user.tempstore', 'Drupal\user\TempStoreFactory')
+      ->addArgument(new Reference('database'))
+      ->addArgument(new Reference('lock'));
+    $container->register('twig', 'Drupal\Core\Template\TwigEnvironment')
+      ->setFactoryClass('Drupal\Core\Template\TwigFactory')
+      ->setFactoryMethod('get');
+
+    // Add the entity query factory.
+    $container->register('entity.query', 'Drupal\Core\Entity\Query\QueryFactory')
+      ->addArgument(new Reference('service_container'));
+
+    $container->register('router.dumper', 'Drupal\Core\Routing\MatcherDumper')
+      ->addArgument(new Reference('database'));
+    $container->register('router.builder', 'Drupal\Core\Routing\RouteBuilder')
+      ->addArgument(new Reference('router.dumper'))
+      ->addArgument(new Reference('lock'))
+      ->addArgument(new Reference('dispatcher'));
+
+
+    $container->register('matcher', 'Drupal\Core\Routing\ChainMatcher');
+    $container->register('legacy_url_matcher', 'Drupal\Core\LegacyUrlMatcher')
+      ->addTag('chained_matcher');
+    $container->register('nested_matcher', 'Drupal\Core\Routing\NestedMatcher')
+      ->addTag('chained_matcher', array('priority' => 5));
+
+    $container
+      ->register('cache.path', 'Drupal\Core\Cache\CacheBackendInterface')
+      ->setFactoryClass('Drupal\Core\Cache\CacheFactory')
+      ->setFactoryMethod('get')
+      ->addArgument('path');
+
+    $container->register('path.alias_manager.cached', 'Drupal\Core\CacheDecorator\AliasManagerCacheDecorator')
+      ->addArgument(new Reference('path.alias_manager'))
+      ->addArgument(new Reference('cache.path'));
+
+    $container->register('path.crud', 'Drupal\Core\Path\Path')
+      ->addArgument(new Reference('database'))
+      ->addArgument(new Reference('path.alias_manager'));
+
+    // Add password hashing service. The argument to PhpassHashedPassword
+    // constructor is the log2 number of iterations for password stretching.
+    // This should increase by 1 every Drupal version in order to counteract
+    // increases in the speed and power of computers available to crack the
+    // hashes. The current password hashing method was introduced in Drupal 7
+    // with a log2 count of 15.
+    $container->register('password', 'Drupal\Core\Password\PhpassHashedPassword')
+      ->addArgument(16);
+
+    // The following services are tagged as 'nested_matcher' services and are
+    // processed in the RegisterNestedMatchersPass compiler pass. Each one
+    // needs to be set on the matcher using a different method, so we use a
+    // tag attribute, 'method', which can be retrieved and passed to the
+    // addMethodCall() method that gets called on the matcher service in the
+    // compiler pass.
+    $container->register('path_matcher', 'Drupal\Core\Routing\PathMatcher')
+      ->addArgument(new Reference('database'))
+      ->addTag('nested_matcher', array('method' => 'setInitialMatcher'));
+    $container->register('http_method_matcher', 'Drupal\Core\Routing\HttpMethodMatcher')
+      ->addTag('nested_matcher', array('method' => 'addPartialMatcher'));
+    $container->register('mime_type_matcher', 'Drupal\Core\Routing\MimeTypeMatcher')
+      ->addTag('nested_matcher', array('method' => 'addPartialMatcher'));
+    $container->register('first_entry_final_matcher', 'Drupal\Core\Routing\FirstEntryFinalMatcher')
+      ->addTag('nested_matcher', array('method' => 'setFinalMatcher'));
+
+    $container->register('router_processor_subscriber', 'Drupal\Core\EventSubscriber\RouteProcessorSubscriber')
+      ->addTag('event_subscriber');
+    $container->register('router_listener', 'Symfony\Component\HttpKernel\EventListener\RouterListener')
+      ->addArgument(new Reference('matcher'))
+      ->addTag('event_subscriber');
+    $container->register('content_negotiation', 'Drupal\Core\ContentNegotiation');
+    $container->register('view_subscriber', 'Drupal\Core\EventSubscriber\ViewSubscriber')
+      ->addArgument(new Reference('content_negotiation'))
+      ->addTag('event_subscriber');
+    $container->register('legacy_access_subscriber', 'Drupal\Core\EventSubscriber\LegacyAccessSubscriber')
+      ->addTag('event_subscriber');
+    $container->register('access_manager', 'Drupal\Core\Access\AccessManager')
+      ->addArgument(new Reference('request'))
+      ->addMethodCall('setContainer', array(new Reference('service_container')));
+    $container->register('access_subscriber', 'Drupal\Core\EventSubscriber\AccessSubscriber')
+      ->addArgument(new Reference('access_manager'))
+      ->addTag('event_subscriber');
+    $container->register('access_check.default', 'Drupal\Core\Access\DefaultAccessCheck')
+      ->addTag('access_check');
+    $container->register('access_check.permission', 'Drupal\Core\Access\PermissionAccessCheck')
+      ->addTag('access_check');
+    $container->register('maintenance_mode_subscriber', 'Drupal\Core\EventSubscriber\MaintenanceModeSubscriber')
+      ->addTag('event_subscriber');
+    $container->register('path_subscriber', 'Drupal\Core\EventSubscriber\PathSubscriber')
+      ->addArgument(new Reference('path.alias_manager.cached'))
+      ->addTag('event_subscriber');
+    $container->register('legacy_request_subscriber', 'Drupal\Core\EventSubscriber\LegacyRequestSubscriber')
+      ->addTag('event_subscriber');
+    $container->register('legacy_controller_subscriber', 'Drupal\Core\EventSubscriber\LegacyControllerSubscriber')
+      ->addTag('event_subscriber');
+    $container->register('finish_response_subscriber', 'Drupal\Core\EventSubscriber\FinishResponseSubscriber')
+      ->addArgument(new Reference('language_manager'))
+      ->setScope('request')
+      ->addTag('event_subscriber');
+    $container->register('request_close_subscriber', 'Drupal\Core\EventSubscriber\RequestCloseSubscriber')
+      ->addTag('event_subscriber');
+    $container->register('config_global_override_subscriber', 'Drupal\Core\EventSubscriber\ConfigGlobalOverrideSubscriber')
+      ->addTag('event_subscriber');
+    $container->register('exception_listener', 'Drupal\Core\EventSubscriber\ExceptionListener')
+      ->addTag('event_subscriber')
+      ->addArgument(new Reference('service_container'))
+      ->setFactoryClass('Drupal\Core\ExceptionController')
+      ->setFactoryMethod('getExceptionListener');
+
+    $container
+      ->register('transliteration', 'Drupal\Core\Transliteration\PHPTransliteration');
+
+    // Add Serializer with arguments to be replaced in the compiler pass.
+    $container->register('serializer', 'Symfony\Component\Serializer\Serializer')
+      ->addArgument(array())
+      ->addArgument(array());
+
+    $container->register('flood', 'Drupal\Core\Flood\DatabaseBackend')
+      ->addArgument(new Reference('database'));
+
+    $container->addCompilerPass(new RegisterMatchersPass());
+    $container->addCompilerPass(new RegisterNestedMatchersPass());
+    // Add a compiler pass for registering event subscribers.
+    $container->addCompilerPass(new RegisterKernelListenersPass(), PassConfig::TYPE_AFTER_REMOVING);
+    // Add a compiler pass for adding Normalizers and Encoders to Serializer.
+    $container->addCompilerPass(new RegisterSerializationClassesPass());
+    // Add a compiler pass for registering event subscribers.
+    $container->addCompilerPass(new RegisterKernelListenersPass(), PassConfig::TYPE_AFTER_REMOVING);
+    $container->addCompilerPass(new RegisterAccessChecksPass());
+  }
+
+}
diff --git a/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterEntityParamConvertersPass.php b/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterEntityParamConvertersPass.php
new file mode 100644
index 0000000..f787065
--- /dev/null
+++ b/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterEntityParamConvertersPass.php
@@ -0,0 +1,35 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\Core\DependencyInjection\Compiler\RegisterEntityParamConvertersPass.
+ */
+
+namespace Drupal\Core\DependencyInjection\Compiler;
+
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
+
+/**
+ * Registers EntityConverter services with the ParamConverterManager.
+ */
+class RegisterEntityParamConvertersPass implements CompilerPassInterface {
+
+  /**
+   * Adds 'paramconverter.entity' services 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');
+    foreach ($container->findTaggedServiceIds('paramconverter.entity') as $id => $attributes) {
+      $manager->addMethodCall('addConverterService', array($id, $attributes[0]['classname']));
+    }
+  }
+
+}
diff --git a/core/lib/Drupal/Core/EventSubscriber/ParamConverterSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/ParamConverterSubscriber.php
new file mode 100644
index 0000000..d4d15db
--- /dev/null
+++ b/core/lib/Drupal/Core/EventSubscriber/ParamConverterSubscriber.php
@@ -0,0 +1,71 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\Core\EventSubscriber\ParamConverterSubscriber.
+ */
+
+namespace Drupal\Core\EventSubscriber;
+
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpKernel\KernelEvents;
+use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+use Drupal\Core\ParamConverter\ParamConverterManager;
+
+/**
+ * Handles converting request attributes to their appropriate objects.
+ */
+class ParamConverterSubscriber implements EventSubscriberInterface {
+
+  /**
+   * Broker object that handles actually converting parameters.
+   *
+   * @var \Drupal\Core\ParamConverter\ParamConverterManager
+   */
+  protected $paramConverterManager;
+
+  /**
+   * Constructs a new ParamConverterSubscriber.
+   *
+   * @param Drupal\Core\ParamConverter\ParamConverterManager $manager
+   *   The converter manager that will be responsible for converting
+   *   request attributes into their corresponding object values.
+   */
+  public function __construct(ParamConverterManager $manager) {
+    $this->paramConverterManager = $manager;
+  }
+
+  /**
+   * Response with the maintenance page when the site is offline.
+   *
+   * @param Symfony\Component\HttpKernel\Event\FilterControllerEvent $event
+   *   The Event to process.
+   */
+  public function onKernelControllerParamConverter(FilterControllerEvent $event) {
+    $request = $event->getRequest();
+
+    // If this is a legacy request, skip it as we're not doing conversion for
+    // those.
+    // @todo Remove this check once we eliminate the legacy router.
+    if ($request->attributes->has('drupal_menu_item')) {
+      return;
+    }
+
+    $controller = $event->getController();
+
+    $this->paramConverterManager->applyToRequest($controller, $request);
+  }
+
+  /**
+   * Registers the methods in this class that should be listeners.
+   *
+   * @return array
+   *   An array of event listener definitions.
+   */
+  static function getSubscribedEvents() {
+    $events[KernelEvents::CONTROLLER][] = array('onKernelControllerParamConverter', 40);
+    return $events;
+  }
+
+}
diff --git a/core/lib/Drupal/Core/ParamConverter/EntityConverter.php b/core/lib/Drupal/Core/ParamConverter/EntityConverter.php
new file mode 100644
index 0000000..f264727
--- /dev/null
+++ b/core/lib/Drupal/Core/ParamConverter/EntityConverter.php
@@ -0,0 +1,45 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\Core\ParamConverter\EntityConverter.
+ */
+
+namespace Drupal\Core\ParamConverter;
+
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Parameter converter for entities.
+ *
+ * Each entity type needs to be registered on ParamConverterManager
+ * independently, but all entities can use the same converter.
+ */
+class EntityConverter implements ParamConverterInterface {
+
+  /**
+   * Implements ParamConverterInterface::convert().
+   */
+  public function convert(Request $request, $value, $class, array $arguments = array()) {
+    // Try to retrieve the entity type of the given entity class.
+    foreach (entity_get_info() as $key => $entity_info) {
+      if ($entity_info['class'] == $class) {
+        $entity_type = $key;
+        break;
+      }
+    }
+
+    // Throw an exception if we don't know about the class we're being asked to
+    // convert to.
+    if (!isset($entity_type)) {
+      throw new \InvalidArgumentException("No entity found that uses class $class.");
+    }
+
+    // Load the entity loader, then use it to load the object.
+    // Once again, this should be coming from the Service Container eventually.
+    if ($entities = entity_get_controller($entity_type)->load(array($value))) {
+      return reset($entities);
+    }
+  }
+
+}
diff --git a/core/lib/Drupal/Core/ParamConverter/EntityConverterFactory.php b/core/lib/Drupal/Core/ParamConverter/EntityConverterFactory.php
new file mode 100644
index 0000000..2c37238
--- /dev/null
+++ b/core/lib/Drupal/Core/ParamConverter/EntityConverterFactory.php
@@ -0,0 +1,39 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\Core\ParamConverter\EntityConverterFactory.
+ */
+
+namespace Drupal\Core\ParamConverter;
+
+/**
+ * Factory class for the EntityConverter.
+ *
+ * We only ever need one instance of the EntityConverter but every module that
+ * provides an entity type needs to register a service for it. So we use a
+ * factory to return the same instance for each service.
+ */
+class EntityConverterFactory {
+
+  /**
+   * Holds the instantiated EntityConverter object.
+   *
+   * @var \Drupal\Core\ParamConverter\EntityConverter
+   */
+  static protected $converter;
+
+  /**
+   * Returns an EntityConverter object.
+   *
+   * @return \Drupal\Core\ParamConverter\EntityConverter
+   *   The parameter converter for entities.
+   */
+  public static function getParamConverter() {
+    if (!isset(static::$converter)) {
+      static::$converter = new EntityConverter();
+    }
+    return static::$converter;
+  }
+
+}
diff --git a/core/lib/Drupal/Core/ParamConverter/ParamConverterInterface.php b/core/lib/Drupal/Core/ParamConverter/ParamConverterInterface.php
new file mode 100644
index 0000000..3f979ce
--- /dev/null
+++ b/core/lib/Drupal/Core/ParamConverter/ParamConverterInterface.php
@@ -0,0 +1,32 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\Core\ParamConverter\ParamConverterInterface.
+ */
+
+namespace Drupal\Core\ParamConverter;
+
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Interface for parameter converters.
+ */
+interface ParamConverterInterface {
+
+  /**
+   * Converts the provided value to an object of type $class.
+   *
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   *   The request object.
+   * @param mixed $value
+   *   The value to upcast to an object.
+   * @param string $class
+   *   The fully qualified name of the class to convert to.
+   * @param array $arguments
+   *   (optional) An array of arguments to direct the converter how to behave.
+   *   These values will vary with the converter.
+   */
+   public function convert(Request $request, $value, $class, array $arguments = array());
+
+}
diff --git a/core/lib/Drupal/Core/ParamConverter/ParamConverterManager.php b/core/lib/Drupal/Core/ParamConverter/ParamConverterManager.php
new file mode 100644
index 0000000..fb1c8cf
--- /dev/null
+++ b/core/lib/Drupal/Core/ParamConverter/ParamConverterManager.php
@@ -0,0 +1,153 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\Core\ParamConverter\ParamConverterManager.
+ */
+
+namespace Drupal\Core\ParamConverter;
+
+use Symfony\Component\DependencyInjection\ContainerAware;
+use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * This class manages conversion of request attributes to typed objects.
+ */
+class ParamConverterManager extends ContainerAware {
+
+  /**
+   * Array of Converter services to apply.
+   *
+   * The array keys are fully qualified class names; The value is an associative
+   * array containing service_id (the ID of the container service that provides
+   * the corresponding converter) and arguments, which is an associative array
+   * of options to pass to the converter at conversion time.
+   *
+   * @var array
+   */
+  protected $converterIds;
+
+  /**
+   * Array of instantiated converter objects.
+   *
+   * The array keys are full qualified class names; the values are the
+   * instantiated converter object.
+   *
+   * @var array
+   */
+  protected $converters;
+
+  /**
+   * Registers a service as a converter.
+   *
+   * @param string $service
+   *   The ID of a parameter converter service.
+   * @param string $classname
+   *   The fully qualified class name that should use this converter.
+   * @param array $arguments
+   *   (optional) An array of arguments that should be passed to the converter
+   *   on invocation.
+   *
+   * @return \Drupal\Core\ParamConverter\ParamConverterManager
+   *   The called object.
+   */
+  public function addConverterService($service, $classname, array $arguments = array()) {
+    $this->converterIds[$classname] = array(
+      'service' => $service,
+      'arguments' => $arguments,
+    );
+
+    return $this;
+  }
+
+  /**
+   * Converts all request attributes based on type hints on the controller.
+   *
+   * @param callable $controller
+   *   The controller that is to be called.
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   *   The request object to convert.
+   *
+   * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
+   *   Thrown when a request attribute could not be properly converted.
+   */
+  public function applyToRequest($controller, Request $request) {
+    $args = $request->attributes;
+    
+    $route = $args->get('_route');
+    
+    if (empty($route)) { return; }
+    
+    // Obtain placeholder names from request attributes.
+    $placeholders = $args->keys();
+    foreach ($placeholders as $i => $key) {
+      if ($key[0] == '_' || $key == 'system_path') {
+        unset($placeholders[$i]);
+      }
+    }
+    
+    // Get converters defined in the route definition.
+    $configuredConverter = $args->get('_route')->getOption('converters');
+    
+    // Apply defined converters or guess them from the name of the placeholder.
+    // Anything else will simply pass without any upcasting.
+    foreach ($placeholders as $i => $key) {
+      $guessedConverter = "Drupal\\$key\\Plugin\\Core\\Entity\\" . ucfirst($key);
+      if (isset($configuredConverter[$key])) {
+        $upcastArgs[$key] = $configuredConverter[$key];
+      }
+      elseif (class_exists($guessedConverter)) {
+        $upcastArgs[$key] = $guessedConverter;
+      }
+    }
+
+    // Upcast everything we can.
+    foreach ($upcastArgs as $key => $converter ) {
+      $convert = $this->convertTo($request, $args->get($key), $converter);
+      if (is_object($convert)) {
+        $request->attributes->set($key, $convert);
+      }
+    }
+  }
+  /**
+   * Converts a value to the specified classname.
+   *
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   *   The request object.
+   * @param mixed $value
+   *   The value to convert. It may be of any type other than object.
+   * @param string $classname
+   *   The fully qualified name of the class to which to convert the value.
+   *
+   * @return object
+   *   An object of type $classname based on $value.
+   */
+  public function convertTo(Request $request, $value, $classname) {
+    return $this->getConverter($classname)->convert($request, $value, $classname, $this->converterIds[$classname]['arguments']);
+  }
+
+  /**
+   * Retrieves a converter for the provided class.
+   *
+   * @param string $classname
+   *   The fully qualified name of the class for which to load the converter.
+   *
+   * @return \Drupal\Core\ParamConverter\ParamConverterInterface
+   *   The converter for the provided class.
+   *
+   * @throws \InvalidArgumentException
+   *   Thrown in case the given class is not registered as a converter.
+   */
+  protected function getConverter($classname) {
+    if (!empty($this->converters[$classname])) {
+      return $this->converters[$classname];
+    }
+    if (empty($this->converterIds[$classname])) {
+      throw new \InvalidArgumentException(sprintf('No converter has been registered for %s.', $classname));
+    }
+    $this->converters[$classname] = $this->container->get($this->converterIds[$classname]['service']);
+    return $this->converters[$classname];
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Routing/RouteBuilder.php b/core/lib/Drupal/Core/Routing/RouteBuilder.php
index fc12ee8..6f7a86e 100644
--- a/core/lib/Drupal/Core/Routing/RouteBuilder.php
+++ b/core/lib/Drupal/Core/Routing/RouteBuilder.php
@@ -87,7 +87,8 @@ public function rebuild() {
           foreach ($routes as $name => $route_info) {
             $defaults = isset($route_info['defaults']) ? $route_info['defaults'] : array();
             $requirements = isset($route_info['requirements']) ? $route_info['requirements'] : array();
-            $route = new Route($route_info['pattern'], $defaults, $requirements);
+            $options = isset($route_info['options']) ? $route_info['options'] : array();
+            $route = new Route($route_info['pattern'], $defaults, $requirements, $options);
             $collection->add($name, $route);
           }
         }
diff --git a/core/modules/node/lib/Drupal/node/NodeBundle.php b/core/modules/node/lib/Drupal/node/NodeBundle.php
new file mode 100644
index 0000000..c104222
--- /dev/null
+++ b/core/modules/node/lib/Drupal/node/NodeBundle.php
@@ -0,0 +1,40 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\node\NodeBundle.
+ */
+
+namespace Drupal\node;
+
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\HttpKernel\Bundle\Bundle;
+
+/**
+ * Defines the node module bundle.
+ */
+class NodeBundle extends Bundle {
+
+  /**
+   * Overrides \Symfony\Component\HttpKernel\Bundle\Bundle::build().
+   *
+   * The job of converting an entity id to an entity object for controllers
+   * expecting an object is done by an EntityConverter. We register a service
+   * using the EntityConverterFactory (which ensures only one EntityConverter
+   * is instantiated for all entity types) and tag it so that the compiler
+   * pass will add it to the ParamConverterManager, using the classname
+   * attribute to tell it that the 'Drupal\node\Plugin\Core\Entity\Node' class
+   * can be converted using the EntityConverter.
+   *
+   * @see \Drupal\Core\ParamConverter\EntityConverter
+   * @see \Drupal\Core\ParamConverter\ParamConverterManager
+   * @see \Drupal\Core\DependencyInjection\Compiler\RegisterEntityParamConverterPass
+   */
+  public function build(ContainerBuilder $container) {
+    $container->register('paramconverter.entity.node', 'Drupal\Core\ParamConverter\EntityConverter')
+      ->setFactoryClass('Drupal\Core\ParamConverter\EntityConverterFactory')
+      ->setFactoryMethod('getParamConverter')
+      ->addTag('paramconverter.entity', array('classname' => 'Drupal\node\Plugin\Core\Entity\Node'));
+  }
+
+}
diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index ea2b4ce..a37679c 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -3028,8 +3028,8 @@ function node_query_node_access_alter(AlterableInterface $query) {
   }
 
   // If $account can bypass node access, or there are no node access modules,
-  // or the operation is 'view' and the $acount has a global view grant (i.e.,
-  // a view grant for node ID 0), we don't need to alter the query.
+  // or the operation is 'view' and the $account has a global view grant
+  // (such as a view grant for node ID 0), we don't need to alter the query.
   if (user_access('bypass node access', $account)) {
     return;
   }
diff --git a/core/modules/system/lib/Drupal/system/Tests/ParamConverter/MockConverter.php b/core/modules/system/lib/Drupal/system/Tests/ParamConverter/MockConverter.php
new file mode 100644
index 0000000..a5f4231
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/Tests/ParamConverter/MockConverter.php
@@ -0,0 +1,30 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\system\Tests\ParamConverter\MockConverter.
+ */
+
+namespace Drupal\system\Tests\ParamConverter;
+
+use Symfony\Component\HttpFoundation\Request;
+
+use Drupal\Core\ParamConverter\ParamConverterInterface;
+
+/**
+ * Fake ParamConverter for testing.
+ */
+class MockConverter implements ParamConverterInterface {
+
+  /**
+   * Implements \Drupal\Core\ParamConverter\ParamConverterInterface::convert().
+   */
+  public function convert(Request $request, $value, $class, array $arguments = array()) {
+    if ($value === FALSE) {
+      return;
+    }
+    return new MockType($value);
+  }
+
+}
+
diff --git a/core/modules/system/lib/Drupal/system/Tests/ParamConverter/MockType.php b/core/modules/system/lib/Drupal/system/Tests/ParamConverter/MockType.php
new file mode 100644
index 0000000..aa3999b
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/Tests/ParamConverter/MockType.php
@@ -0,0 +1,21 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\system\Tests\ParamConverter\MockConverter.
+ */
+
+namespace Drupal\system\Tests\ParamConverter;
+
+/**
+ * Fake class for testing.
+ */
+class MockType {
+
+  public $value;
+
+  public function __construct($value) {
+    $this->value = $value;
+  }
+
+}
diff --git a/core/modules/system/lib/Drupal/system/Tests/ParamConverter/ParamConverterManagerTest.php b/core/modules/system/lib/Drupal/system/Tests/ParamConverter/ParamConverterManagerTest.php
new file mode 100644
index 0000000..8c00d39
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/Tests/ParamConverter/ParamConverterManagerTest.php
@@ -0,0 +1,127 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\system\Tests\ParamConverter\ParamConverterManagerTest.
+ */
+
+namespace Drupal\system\Tests\ParamConverter;
+
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
+use Drupal\Core\DependencyInjection\ContainerBuilder;
+use Drupal\Core\ParamConverter\ParamConverterManager;
+use Drupal\simpletest\UnitTestBase;
+
+/**
+ * Basic tests for the ParamConverter.
+ */
+class ParamConverterManagerTest extends UnitTestBase {
+
+  /**
+   * A simple container for testing purposes.
+   *
+   * @var \Drupal\Core\DependencyInjection\ContainerBuilder
+   */
+  protected $mockContainer;
+
+  public static function getInfo() {
+    return array(
+      'name' => 'ParamConverter Manager tests',
+      'description' => 'Confirm that the ParamConverterMatcher is working correctly.',
+      'group' => 'Routing',
+    );
+  }
+
+  public function setUp() {
+    parent::setUp();
+
+    $this->mockContainer = new ContainerBuilder();
+    $this->mockContainer->register('test_converter', 'Drupal\system\Tests\ParamConverter\MockConverter');
+  }
+
+  /**
+   * Confirms that a parameter is converted when expected.
+   */
+  public function testParamConverted() {
+    $converter = new ParamConverterManager();
+    $converter->setContainer($this->mockContainer);
+    $converter->addConverterService('test_converter', 'Drupal\system\Tests\ParamConverter\MockType');
+
+    $request = Request::create('/foo/{bar}');
+    $request->attributes->set('bar', 1);
+
+    $controller = function (MockType $bar) {};
+    $converter->applyToRequest($controller, $request);
+
+    $this->assertTrue($request->attributes->get('bar') instanceof MockType, 'The parameter was upcast successfully.');
+  }
+
+
+  /**
+   * Confirms that un-hinted parameters are not affected.
+   */
+  public function testParamNoConversionNeeded() {
+    $converter = new ParamConverterManager();
+    $converter->setContainer($this->mockContainer);
+    $converter->addConverterService('test_converter', 'Drupal\system\Tests\ParamConverter\MockType');
+
+    $request = Request::create('/foo/{bar}/{baz}');
+    $request->attributes->set('bar', 1);
+    $request->attributes->set('baz', 2);
+
+    $controller = function (MockType $bar, $baz) {};
+    $converter->applyToRequest($controller, $request);
+
+    $this->assertTrue($request->attributes->get('bar') instanceof MockType, 'Hinted parameter was upcast successfully.');
+    $this->assertEqual($request->attributes->get('baz'), 2, 'Bare parameter was not changed.');
+  }
+
+  /**
+   * Confirms that if a parameter could not be converted an exception is thrown.
+   */
+  public function testConversionFailed() {
+    $converter = new ParamConverterManager();
+    $converter->setContainer($this->mockContainer);
+    $converter->addConverterService('test_converter', 'Drupal\system\Tests\ParamConverter\MockType');
+
+    $request = Request::create('/foo/{bar}');
+    $request->attributes->set('bar', FALSE);
+
+    $controller = function (MockType $bar) {};
+
+    try {
+      $converter->applyToRequest($controller, $request);
+    }
+    catch (NotFoundHttpException $e) {
+      $this->pass('NotFoundHttpException thrown for a value that could not be converted.');
+      return;
+    }
+
+    $this->fail('No exception thrown for a value that could not be converted.');
+  }
+
+  /**
+   * Confirms that if a parameter is not convertable an exceptoin is thrown.
+   */
+  public function testNoTypeRegistered() {
+    $converter = new ParamConverterManager();
+    $converter->setContainer($this->mockContainer);
+
+    $request = Request::create('/foo/{bar}');
+    $request->attributes->set('bar', 1);
+
+    $controller = function (MockType $bar) {};
+
+    try {
+      $converter->applyToRequest($controller, $request);
+    }
+    catch (\InvalidArgumentException $e) {
+      $this->pass('InvalidArgumentException thrown for an unregistered type.');
+      return;
+    }
+
+    $this->fail('No exception thrown for unregisterd type.');
+  }
+
+}
diff --git a/core/modules/system/lib/Drupal/system/Tests/Routing/ParamConverterTest.php b/core/modules/system/lib/Drupal/system/Tests/Routing/ParamConverterTest.php
new file mode 100644
index 0000000..c6118c2
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/Tests/Routing/ParamConverterTest.php
@@ -0,0 +1,61 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\system\Tests\ParamConverterTest.
+ */
+
+namespace Drupal\system\Tests\Routing;
+
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\Routing\Matcher\RequestMatcherInterface;
+use Symfony\Component\Routing\Exception\ResourceNotFoundException;
+use Symfony\Component\Routing\Exception\RouteNotFoundException;
+use Symfony\Component\Routing\Exception\MethodNotAllowedException;
+
+use Drupal\simpletest\WebTestBase;
+
+/**
+ * Basic tests for the ParamConverter.
+ */
+class ParamConverterTest extends WebTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('block', 'router_test');
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Parameter Conversion tests',
+      'description' => 'Function Tests for parameter conversion.',
+      'group' => 'Routing',
+    );
+  }
+
+  /**
+   * Confirms that we can successfully use a route with converted parameter.
+   */
+  public function testCanRoute() {
+    $user = $this->drupalCreateUser();
+    $this->drupalGet('router_test/test9/' . $user->id());
+    $this->assertRaw($user->label(), 'The correct user name was found, and there were no fatal errors.');
+
+    $title = $this->randomString();
+    $node = $this->drupalCreateNode(array(
+      'title' => $title,
+    ));
+    $this->drupalGet('router_test/test10/' . $node->id());
+    $this->assertRaw($title, 'The correct node title was found, and there were no fatal errors.');
+
+    $title = $this->randomString();
+    $other_node = $this->drupalCreateNode(array(
+      'title' => $title,
+    ));
+    $this->drupalGet('router_test/test_node_node/' . $node->id() . '/' . $other_node->id());
+    $this->assertRaw('node: ' . $node->title . ', other_node: ' . $other_node->title, 'The correct node titles were found, and there were no fatal errors.');
+  }
+
+}
diff --git a/core/modules/system/tests/modules/router_test/lib/Drupal/router_test/TestControllers.php b/core/modules/system/tests/modules/router_test/lib/Drupal/router_test/TestControllers.php
index adb5c34..0e6e680 100644
--- a/core/modules/system/tests/modules/router_test/lib/Drupal/router_test/TestControllers.php
+++ b/core/modules/system/tests/modules/router_test/lib/Drupal/router_test/TestControllers.php
@@ -8,6 +8,9 @@
 namespace Drupal\router_test;
 
 use Symfony\Component\HttpFoundation\Response;
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\node\Plugin\Core\Entity\Node;
+use Drupal\user\Plugin\Core\Entity\User;
 
 /**
  * Controller routines for testing the routing system.
@@ -46,4 +49,15 @@ public function test8() {
     return new Response('test8');
   }
 
+  public function test9(User $user) {
+    return $user->label();
+  }
+
+  public function test10(Node $node) {
+    return $node->label();
+  }
+  
+  public function test_node_node(Node $node, Node $other_node) {
+    return 'node: ' . $node->title . ', other_node: ' . $other_node->title;
+  }
 }
diff --git a/core/modules/system/tests/modules/router_test/router_test.info b/core/modules/system/tests/modules/router_test/router_test.info
index d729865..aca88d8 100644
--- a/core/modules/system/tests/modules/router_test/router_test.info
+++ b/core/modules/system/tests/modules/router_test/router_test.info
@@ -3,4 +3,4 @@ description = "Support module for routing testing."
 package = Testing
 version = VERSION
 core = 8.x
-hidden = TRUE
+hidden = FALSE
diff --git a/core/modules/system/tests/modules/router_test/router_test.routing.yml b/core/modules/system/tests/modules/router_test/router_test.routing.yml
index 2c94ff2..36883f4 100644
--- a/core/modules/system/tests/modules/router_test/router_test.routing.yml
+++ b/core/modules/system/tests/modules/router_test/router_test.routing.yml
@@ -45,3 +45,27 @@ router_test_8:
   pattern: '/router_test/test8'
   defaults:
     _controller: '\Drupal\router_test\TestControllers::test8'
+
+router_test_9:
+  pattern: '/router_test/test9/{user}'
+  defaults:
+    _content: '\Drupal\router_test\TestControllers::test9'
+  requirements:
+    _access: 'TRUE'
+
+router_test_10:
+  pattern: '/router_test/test10/{node}'
+  defaults:
+    _content: '\Drupal\router_test\TestControllers::test10'
+  requirements:
+    _access: 'TRUE'
+
+router_test_node_node:
+  pattern: '/router_test/test_node_node/{node}/{other_node}'
+  defaults:
+    _content: '\Drupal\router_test\TestControllers::test_node_node'
+  requirements:
+    _access: 'TRUE'
+  options:
+    converters:
+      other_node: 'Drupal\node\Plugin\Core\Entity\Node'
diff --git a/core/modules/user/lib/Drupal/user/UserBundle.php b/core/modules/user/lib/Drupal/user/UserBundle.php
index a4e7d8d..087925c 100644
--- a/core/modules/user/lib/Drupal/user/UserBundle.php
+++ b/core/modules/user/lib/Drupal/user/UserBundle.php
@@ -25,5 +25,9 @@ public function build(ContainerBuilder $container) {
     $container
       ->register('user.data', 'Drupal\user\UserData')
       ->addArgument(new Reference('database'));
+    $container->register('paramconverter.entity.user', 'Drupal\Core\ParamConverter\EntityConverter')
+      ->setFactoryClass('Drupal\Core\ParamConverter\EntityConverterFactory')
+      ->setFactoryMethod('getParamConverter')
+      ->addTag('paramconverter.entity', array('classname' => 'Drupal\user\Plugin\Core\Entity\User'));
   }
 }
