diff --git a/composer.json b/composer.json
index 436dae9..eaa70be 100644
--- a/composer.json
+++ b/composer.json
@@ -36,5 +36,8 @@
   "config": {
     "vendor-dir": "core/vendor",
     "preferred-install": "dist"
+  },
+  "scripts": {
+    "post-autoload-dump": "Drupal\\Core\\Autoload\\GeneratorScript::postAutoloadDump"
   }
 }
diff --git a/core/autoload.drupal.php b/core/autoload.drupal.php
new file mode 100644
index 0000000..e665445
--- /dev/null
+++ b/core/autoload.drupal.php
@@ -0,0 +1,23 @@
+<?php
+
+/**
+ * @file
+ * Drupal-specific autoload.php to be copied to replace core/vendor/autoload.php
+ * generated by Composer.
+ *
+ * Having a Drupal-specific autoload.php makes it easier to use a ClassLoader
+ * implementation different from the one provided by Composer.
+ *
+ * The file will be copied to replace core/vendor/autoload.php, by a script
+ * triggered after composer autoload-dump. That script is in
+ * Drupal\Core\Autoload\GeneratorScript::postAutoloadDump().
+ *
+ * This means, the official autoload.php to include in scripts will always be
+ * core/vendor/autoload.php.
+ */
+
+use Drupal\Core\Autoload\DrupalAutoloaderInit;
+
+require_once dirname(__DIR__) . '/lib/Drupal/Core/Autoload/DrupalAutoloaderInit.php';
+
+return DrupalAutoloaderInit::getLoader();
diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index 109ff24..1c29dbf 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -2725,7 +2725,7 @@ function arg($index = NULL, $path = NULL) {
  *   loader class when calling drupal_classloader() from settings.php. It is
  *   ignored otherwise.
  *
- * @return \Composer\Autoload\ClassLoader
+ * @return \Drupal\Core\Autoload\ClassLoader
  *   A ClassLoader class instance (or extension thereof).
  */
 function drupal_classloader($class_loader = NULL) {
@@ -2767,7 +2767,10 @@ function drupal_classloader($class_loader = NULL) {
  */
 function drupal_classloader_register($name, $path) {
   $loader = drupal_classloader();
-  $loader->add('Drupal\\' . $name, DRUPAL_ROOT . '/' . $path . '/lib');
+  $loader->addPsr4('Drupal\\' . $name . '\\', array(
+    DRUPAL_ROOT . '/' . $path . '/lib/Drupal/' . $name,
+    DRUPAL_ROOT . '/' . $path . '/lib',
+  ));
 }
 
 /**
diff --git a/core/lib/Drupal/Component/Annotation/Plugin/Discovery/AnnotatedClassDiscovery.php b/core/lib/Drupal/Component/Annotation/Plugin/Discovery/AnnotatedClassDiscovery.php
index bdf1eba..6e8a0c6 100644
--- a/core/lib/Drupal/Component/Annotation/Plugin/Discovery/AnnotatedClassDiscovery.php
+++ b/core/lib/Drupal/Component/Annotation/Plugin/Discovery/AnnotatedClassDiscovery.php
@@ -98,7 +98,6 @@ public function getDefinitions() {
     // Search for classes within all PSR-0 namespace locations.
     foreach ($this->getPluginNamespaces() as $namespace => $dirs) {
       foreach ($dirs as $dir) {
-        $dir .= DIRECTORY_SEPARATOR . str_replace('\\', DIRECTORY_SEPARATOR, $namespace);
         if (file_exists($dir)) {
           foreach (new \DirectoryIterator($dir) as $fileinfo) {
             // @todo Once core requires 5.3.6, use $fileinfo->getExtension().
diff --git a/core/lib/Drupal/Core/Autoload/ClassLoader.php b/core/lib/Drupal/Core/Autoload/ClassLoader.php
new file mode 100644
index 0000000..8b5f03e
--- /dev/null
+++ b/core/lib/Drupal/Core/Autoload/ClassLoader.php
@@ -0,0 +1,526 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\Core\Autoload\ClassLoader.
+ */
+
+namespace Drupal\Core\Autoload;
+
+/**
+ * Implements a class loader for PSR-0 and the proposed PSR-4. See
+ * - https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md
+ * - https://github.com/pmjones/fig-standards/blob/master/proposed/psr-4-autoloader/psr-4-autolader.md
+ *
+ * The class is mostly based on:
+ * 1. A pull request for Composer, that will add PSR-4 class loading to
+ *    Composer\Autoload\ClassLoader.
+ *    See https://github.com/composer/composer/pull/2121.
+ * 2. A change proposed to Composer, that will improve autoload performance in
+ *    cases where many of the registered namespaces have the same first
+ *    character. E.g. many sub-namespaces of 'Drupal\\', where the first
+ *    character is always 'D'.
+ *    See https://github.com/composer/composer/issues/2112
+ *
+ * The pull request (1.) has been adapted to comply with the Drupal coding
+ * standards, and enhanced with docblock comments.
+ * The predictor logic (2.) was added to that in a custom fashion.
+ */
+class ClassLoader {
+
+  /**
+   * @var array
+   *   PSR-4 namespaces mapped to their string length, to avoid a strlen() on
+   *   class lookups.
+   *
+   *   Namespaces are represented with trailing namespace separator, but without
+   *   a preceding namespace separator.
+   *
+   *   The array has a nested structure, where namespaces are grouped by
+   *   predictor characters picked at specific positions in the namespace.
+   *   The first position is always [0], the second position is determined by
+   *   self::PREDICTOR_INDEX, which is hardcoded to [9].
+   *   If the namespace is shorter than that, only the first character is used.
+   *
+   *   E.g. a possible value of this variable could be:
+   *
+   *   array(
+   *     'Dr' => array('Drupal\Core\\' => 12),
+   *     'Dm' => array(
+   *       'Drupal\Component\\' => 17,
+   *       'Drupal\number\\' => 14,
+   *     ),
+   *     'S' => array('Symfony\\' => 8),
+   *   )
+   */
+  private $prefixLengthsPsr4 = array();
+
+  /**
+   * @var array
+   *   Namespaces mapped to PSR-4 directories.
+   *
+   *   Namespaces are represented with trailing namespace separator, but without
+   *   a preceding namespace separator.
+   *
+   *   Directories for each namespace are represented as a numeric array.
+   *   The loader is designed to work whether or not the directories have a
+   *   trailing directory separator.
+   *
+   *   E.g. a possible value of this variable could be:
+   *
+   *   array(
+   *     'Drupal\Core\\' => array(DRUPAL_ROOT . '/core/lib/Drupal/Core'),
+   *     'Drupal\Component\\' => array(DRUPAL_ROOT . '/core/lib/Drupal/Component'),
+   *   )
+   */
+  private $prefixDirsPsr4 = array();
+
+  /**
+   * @var array
+   *   PSR-4 directories to use if no matching namespace is found.
+   */
+  private $fallbackDirsPsr4 = array();
+
+  /**
+   * @var array
+   *   Prefixes mapped to PSR-0 directories.
+   *
+   *   The array has a nested structure, where prefixes are grouped by their
+   *   first character.
+   *
+   *   E.g. a possible value of this variable could be:
+   *
+   *   array(
+   *     'D' => array(
+   *       'Drupal\Core\\' => array(DRUPAL_ROOT . '/core/lib'),
+   *       'Drupal\Component\\' => array(DRUPAL_ROOT . '/core/lib'),
+   *       'Drupal\system\\' => array(DRUPAL_ROOT . '/core/modules/system/lib'),
+   *     ),
+   *     'S' => array(
+   *       'Symfony\Component\Routing\\' => array(..),
+   *       'Symfony\Component\Process\\' => array(..),
+   *     ),
+   *   ),
+   */
+  private $prefixesPsr0 = array();
+
+  /**
+   * @var array
+   *   PSR-0 directories to use if no matching prefix is found.
+   */
+  private $fallbackDirsPsr0 = array();
+
+  /**
+   * @var bool
+   *   TRUE, if the autoloader uses the include path to check for classes.
+   */
+  private $useIncludePath = FALSE;
+
+  /**
+   * @var array
+   *   Specific classes mapped to specific PHP files.
+   */
+  private $classMap = array();
+
+  /**
+   * @const
+   *   Position in a fully-qualified class name where a character should be
+   *   picked to build the index for $prefixLengthsPsr4.
+   *   The position [9] has been chosen because it provides a good distribution
+   *   of the typical namespaces in a Drupal project.
+   */
+  const PREDICTOR_INDEX = 9;
+
+  /**
+   * Gets the registered prefixes for PSR-0 directories.
+   *
+   * @return array
+   *   Registered prefixes mapped to PSR-0 directories.
+   */
+  public function getPrefixes() {
+    return call_user_func_array('array_merge', $this->prefixesPsr0);
+  }
+
+  /**
+   * Gets the registered namespaces for PSR-4 directories.
+   *
+   * @return array
+   *   Namespaces mapped to PSR-4 directories.
+   */
+  public function getPrefixesPsr4() {
+    return $this->prefixDirsPsr4;
+  }
+
+  /**
+   * Gets the PSR-0 fallback directories.
+   *
+   * @return array
+   *   PSR-0 directories to use if no matching prefix is found.
+   */
+  public function getFallbackDirs() {
+    return $this->fallbackDirsPsr0;
+  }
+
+  /**
+   * Gets the PSR-4 fallback directories.
+   *
+   * @return array
+   *   PSR-0 directories to use if no matching prefix is found.
+   */
+  public function getFallbackDirsPsr4() {
+    return $this->fallbackDirsPsr4;
+  }
+
+  /**
+   * Gets the class map.
+   *
+   * @return array
+   *   Specific classes mapped to specific PHP files.
+   */
+  public function getClassMap() {
+    return $this->classMap;
+  }
+
+  /**
+   * Adds a class map.
+   *
+   * @param array $classMap
+   *   Specific classes mapped to specific PHP files.
+   */
+  public function addClassMap(array $classMap) {
+    if ($this->classMap) {
+      $this->classMap = array_merge($this->classMap, $classMap);
+    }
+    else {
+      $this->classMap = $classMap;
+    }
+  }
+
+  /**
+   * Adds a set of PSR-0 directories for a given prefix.
+   *
+   * The directories will be appended or prepended to the ones previously set
+   * for this prefix, depending on the $prepend parameter.
+   *
+   * @param string $prefix
+   *   The prefix.
+   * @param array|string $paths
+   *   The PSR-0 root directories.
+   * @param bool $prepend
+   *   (optional) Whether to prepend the directories.
+   */
+  public function add($prefix, $paths, $prepend = FALSE) {
+    if (!$prefix) {
+      if ($prepend) {
+        $this->fallbackDirsPsr0 = array_merge(
+          (array) $paths,
+          $this->fallbackDirsPsr0
+        );
+      }
+      else {
+        $this->fallbackDirsPsr0 = array_merge(
+          $this->fallbackDirsPsr0,
+          (array) $paths
+        );
+      }
+
+      return;
+    }
+
+    $first = $prefix[0];
+    if (!isset($this->prefixesPsr0[$first][$prefix])) {
+      $this->prefixesPsr0[$first][$prefix] = (array) $paths;
+
+      return;
+    }
+    if ($prepend) {
+      $this->prefixesPsr0[$first][$prefix] = array_merge(
+        (array) $paths,
+        $this->prefixesPsr0[$first][$prefix]
+      );
+    }
+    else {
+      $this->prefixesPsr0[$first][$prefix] = array_merge(
+        $this->prefixesPsr0[$first][$prefix],
+        (array) $paths
+      );
+    }
+  }
+
+  /**
+   * Adds a set of PSR-4 directories for a given namespace.
+   *
+   * The directories will be appended or prepended to the ones previously set
+   * for this prefix, depending on the $prepend parameter.
+   *
+   * @param string $prefix
+   *   The prefix/namespace, with trailing '\\'.
+   * @param array|string $paths
+   *   The PSR-0 base directories.
+   * @param bool $prepend
+   *   (optional) Whether to prepend the directories.
+   *
+   * @throws \Exception
+   *   Throws an exception if the prefix does not end with a trailing namespace
+   *   separator.
+   */
+  public function addPsr4($prefix, $paths, $prepend = FALSE) {
+    if (!$prefix) {
+      // Register directories for the root namespace.
+      if ($prepend) {
+        $this->fallbackDirsPsr4 = array_merge(
+          (array) $paths,
+          $this->fallbackDirsPsr4
+        );
+      }
+      else {
+        $this->fallbackDirsPsr4 = array_merge(
+          $this->fallbackDirsPsr4,
+          (array) $paths
+        );
+      }
+    }
+    elseif (!isset($this->prefixDirsPsr4[$prefix])) {
+      // Register directories for a new namespace.
+      $length = strlen($prefix);
+      if ('\\' !== $prefix[$length - 1]) {
+        throw new \Exception("A non-empty PSR-4 prefix must end with a namespace separator.");
+      }
+      if ($length > self::PREDICTOR_INDEX) {
+        // The namespace is long enough to have a character at position [9].
+        $predictor = $prefix[0] . $prefix[self::PREDICTOR_INDEX];
+        $this->prefixLengthsPsr4[$predictor][$prefix] = $length;
+      }
+      else {
+        // The namespace is too short to have a character at position [9].
+        $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
+      }
+      $this->prefixDirsPsr4[$prefix] = (array) $paths;
+    }
+    elseif ($prepend) {
+      // Prepend directories for an already registered namespace.
+      $this->prefixDirsPsr4[$prefix] = array_merge(
+        (array) $paths,
+        $this->prefixDirsPsr4[$prefix]
+      );
+    }
+    else {
+      // Append directories for an already registered namespace.
+      $this->prefixDirsPsr4[$prefix] = array_merge(
+        $this->prefixDirsPsr4[$prefix],
+        (array) $paths
+      );
+    }
+  }
+
+  /**
+   * Sets/Overwrites the PSR-0 directories for a given prefix.
+   *
+   * This will replace any directories that were previously set for this prefix.
+   *
+   * @param string $prefix
+   *   The prefix.
+   * @param array|string $paths
+   *   The PSR-0 base directories.
+   */
+  public function set($prefix, $paths) {
+    if (!$prefix) {
+      $this->fallbackDirsPsr0 = (array) $paths;
+    }
+    else {
+      $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
+    }
+  }
+
+  /**
+   * Sets/Overwrites the PSR-4 directories for a given prefix.
+   *
+   * This will replace any directories that were previously set for this prefix.
+   *
+   * @param string $prefix
+   *   The prefix/namespace, with trailing '\\'
+   * @param array|string $paths
+   *   The PSR-4 base directories
+   *
+   * @throws \Exception
+   *   Throws an exception if the prefix does not end with a trailing namespace
+   *   separator.
+   */
+  public function setPsr4($prefix, $paths) {
+    if (!$prefix) {
+      $this->fallbackDirsPsr4 = (array) $paths;
+    }
+    else {
+      $length = strlen($prefix);
+      if ('\\' !== $prefix[$length - 1]) {
+        throw new \Exception("A non-empty PSR-4 prefix must end with a namespace separator.");
+      }
+      if ($length > self::PREDICTOR_INDEX) {
+        $predictor = $prefix[0] . $prefix[self::PREDICTOR_INDEX];
+        $this->prefixLengthsPsr4[$predictor][$prefix] = $length;
+      }
+      else {
+        $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
+      }
+      $this->prefixDirsPsr4[$prefix] = (array) $paths;
+    }
+  }
+
+  /**
+   * Turns on searching the include path for class files.
+   *
+   * @param bool $useIncludePath
+   */
+  public function setUseIncludePath($useIncludePath) {
+    $this->useIncludePath = $useIncludePath;
+  }
+
+  /**
+   * Can be used to check if the autoloader uses the include path to check
+   * for classes.
+   *
+   * @return bool
+   */
+  public function getUseIncludePath() {
+    return $this->useIncludePath;
+  }
+
+  /**
+   * Registers this instance as an autoloader.
+   *
+   * @param bool $prepend
+   *   (optional) Whether to prepend the autoloader or not
+   */
+  public function register($prepend = FALSE) {
+    spl_autoload_register(array($this, 'loadClass'), TRUE, $prepend);
+  }
+
+  /**
+   * Unregisters this instance as an autoloader.
+   */
+  public function unregister() {
+    spl_autoload_unregister(array($this, 'loadClass'));
+  }
+
+  /**
+   * Loads the given class or interface.
+   *
+   * @param string $class
+   *   The name of the class.
+   *
+   * @return bool|NULL
+   *   TRUE if loaded, NULL otherwise.
+   */
+  public function loadClass($class) {
+    if ($file = $this->findFile($class)) {
+      include $file;
+
+      return TRUE;
+    }
+  }
+
+  /**
+   * Finds the path to the file where the class is defined.
+   *
+   * @param string $class
+   *   The name of the class.
+   *
+   * @return string|FALSE
+   *   The path if found, FALSE otherwise.
+   */
+  public function findFile($class) {
+    // work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731.
+    if ('\\' == $class[0]) {
+      $class = substr($class, 1);
+    }
+
+    // class map lookup.
+    if (isset($this->classMap[$class])) {
+      return $this->classMap[$class];
+    }
+
+    // PSR-4 lookup.
+    $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . '.php';
+
+    // Check if the class is in any of the namespaces registered for PSR-4,
+    // and that are long enough to have a character at the predictor index.
+    $first = $class[0];
+    if (isset($class[self::PREDICTOR_INDEX])) {
+      $predictor = $first . $class[self::PREDICTOR_INDEX];
+      if (isset($this->prefixLengthsPsr4[$predictor])) {
+        foreach ($this->prefixLengthsPsr4[$predictor] as $prefix => $length) {
+          if (0 === strpos($class, $prefix)) {
+            foreach ($this->prefixDirsPsr4[$prefix] as $dir) {
+              if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
+                return $file;
+              }
+            }
+          }
+        }
+      }
+    }
+
+    // Check if the class is in any of the namespaces registered for PSR-4,
+    // that are too short to have a character at the predictor index.
+    if (isset($this->prefixLengthsPsr4[$first])) {
+      foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) {
+        if (0 === strpos($class, $prefix)) {
+          foreach ($this->prefixDirsPsr4[$prefix] as $dir) {
+            if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
+              return $file;
+            }
+          }
+        }
+      }
+    }
+
+    // PSR-4 fallback dirs.
+    foreach ($this->fallbackDirsPsr4 as $dir) {
+      if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
+        return $file;
+      }
+    }
+
+    // PSR-0 lookup.
+    if (FALSE !== $pos = strrpos($class, '\\')) {
+      // namespaced class name.
+      $logicalPathPsr0
+        = substr($logicalPathPsr4, 0, $pos + 1)
+        . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR)
+      ;
+    }
+    else {
+      // PEAR-like class name.
+      $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . '.php';
+    }
+
+    // Check if the class matches any of the prefixes registered for PSR-0.
+    if (isset($this->prefixesPsr0[$first])) {
+      foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
+        if (0 === strpos($class, $prefix)) {
+          foreach ($dirs as $dir) {
+            if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
+              return $file;
+            }
+          }
+        }
+      }
+    }
+
+    // PSR-0 fallback dirs.
+    foreach ($this->fallbackDirsPsr0 as $dir) {
+      if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
+        return $file;
+      }
+    }
+
+    // PSR-0 include paths.
+    if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
+      return $file;
+    }
+
+    // Remember that this class does not exist.
+    return $this->classMap[$class] = FALSE;
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Autoload/DrupalAutoloaderInit.php b/core/lib/Drupal/Core/Autoload/DrupalAutoloaderInit.php
new file mode 100644
index 0000000..3f63a17
--- /dev/null
+++ b/core/lib/Drupal/Core/Autoload/DrupalAutoloaderInit.php
@@ -0,0 +1,116 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\Core\Autoload\DrupalAutoloaderInit.
+ */
+
+namespace Drupal\Core\Autoload;
+
+/**
+ * Provides and holds a singleton class loader instance.
+ *
+ * This class is mostly based on the AutoloaderInit generated by Composer, with
+ * the modification that it uses Drupal's own ClassLoader class, instead of the
+ * Composer's ClassLoader class.
+ * Docblock code style has been adapted to Drupal standards, but method
+ * parameters and local variables are lowerCamelCase as in the original code
+ * generated by Composer.
+ */
+class DrupalAutoloaderInit {
+
+  /**
+   * @var \Drupal\Core\Autoload\ClassLoader
+   *   Singleton class loader instance, that is initialized in getLoader().
+   */
+  private static $loader;
+
+  /**
+   * Autoload callback to load the Drupal\Core\Autoload\ClassLoader class.
+   * This would not be strictly needed in Drupal, but it stays here to remain as
+   * close as possible to the AutoloaderInit generated by Composer.
+   *
+   * @param string $class
+   *   The name of the class to load. If this is anything other than
+   *   "Drupal\Core\Autoload\ClassLoader", this method will do nothing.
+   */
+  public static function loadClassLoader($class) {
+    if ('Drupal\Core\Autoload\ClassLoader' === $class) {
+      require __DIR__ . '/ClassLoader.php';
+    }
+  }
+
+  /**
+   * Get the lazy-created class loader instance.
+   *
+   * @return \Drupal\Core\Autoload\ClassLoader
+   *   Singleton instance of the class loader.
+   */
+  public static function getLoader() {
+    // Check if the class loader is already initialized.
+    if (NULL !== self::$loader) {
+      return self::$loader;
+    }
+
+    // Temporarily register an autoload callback to load the
+    // Drupal\Core\Autoload\ClassLoader class. This could be done with a simple
+    // require_once, but instead it is done in the same way as Composer does it.
+    spl_autoload_register(array('Drupal\Core\Autoload\DrupalAutoloaderInit', 'loadClassLoader'), true, true);
+    self::$loader = $loader = new ClassLoader();
+    spl_autoload_unregister(array('Drupal\Core\Autoload\DrupalAutoloaderInit', 'loadClassLoader'));
+
+    // The DRUPAL_ROOT directory. Since the DRUPAL_ROOT constant might not be
+    // available yet, the path is determined relative to this class file.
+    $baseDir = dirname(dirname(dirname(dirname(dirname(__DIR__)))));
+
+    // Directory that contains 3rd party code downloaded by Composer.
+    $vendorDir = $baseDir . '/core/vendor';
+
+    // Directory that contains autoload data generated by Composer.
+    $composerDir = $vendorDir . '/composer';
+
+    // Set the PHP include path.
+    $includePaths = require $composerDir . '/include_paths.php';
+    array_push($includePaths, get_include_path());
+    set_include_path(join(PATH_SEPARATOR, $includePaths));
+
+    // Load PSR-0 namespaces to be registered in the class loader.
+    $map = require $composerDir . '/autoload_namespaces.php';
+
+    // Register core namespaces as PSR-4 instead of PSR-0, to let the autoloader
+    // handle them with priority. These mappings need to be equivalent with the
+    // PSR-0 mappings specified in composer.json. This is only possible because
+    // class names in Drupal core do not contain underscores.
+    // @todo Do this via composer.json, once Composer supports PSR-4.
+    unset($map['Drupal\Core']);
+    unset($map['Drupal\Component']);
+    unset($map['Drupal\Driver']);
+    $loader->setPsr4('Drupal\Core\\', $baseDir . '/core/lib/Drupal/Core');
+    $loader->setPsr4('Drupal\Component\\', $baseDir . '/core/lib/Drupal/Component');
+    $loader->setPsr4('Drupal\Driver\\', $baseDir . '/drivers/lib/Drupal/Driver');
+
+    // Register the remaining PSR-0 namespaces - mostly for vendor libraries.
+    foreach ($map as $namespace => $path) {
+      $loader->set($namespace, $path);
+    }
+
+    // Register the class map in the class loader.
+    $classMap = require $composerDir . '/autoload_classmap.php';
+    if ($classMap) {
+      $loader->addClassMap($classMap);
+    }
+
+    // Register the class loader on the SPL autoload stack.
+    $loader->register(true);
+
+    // Include specific php files, for packages that use the
+    // 'autoload' > 'files' directive in composer.json.
+    $includeFiles = require $composerDir . '/autoload_files.php';
+    foreach ($includeFiles as $file) {
+      require $file;
+    }
+
+    return $loader;
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Autoload/GeneratorScript.php b/core/lib/Drupal/Core/Autoload/GeneratorScript.php
new file mode 100644
index 0000000..f0457ff
--- /dev/null
+++ b/core/lib/Drupal/Core/Autoload/GeneratorScript.php
@@ -0,0 +1,36 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Plugin\Discovery\GeneratorScripts.
+ *
+ * This file is only ever included from Composer commands. This is why it can
+ * use the class Composer\Script\Event, even though this class is not part of
+ * Drupal core, or any vendor libraries shipped with Drupal.
+ */
+
+namespace Drupal\Core\Autoload;
+
+use Composer\Script\Event;
+
+/**
+ * Script to be called after Composer generated the autoload files.
+ */
+class GeneratorScript {
+
+  /**
+   * Replaces the core/vendor/autoload.php with a Drupal-specific autoload.php.
+   *
+   * Registered as a post-autoload-dump callback in composer.json, to be run
+   * every time after Composer has generated the autoload files.
+   *
+   * @param \Composer\Script\Event $event
+   *   Event object provided by Composer.
+   */
+  public static function postAutoloadDump(Event $event) {
+    $core_dir = dirname(dirname(dirname(dirname(__DIR__))));
+    // Replace the generated core/vendor/autoload.php.
+    copy($core_dir . '/autoload.drupal.php', $core_dir . '/vendor/autoload.php');
+  }
+
+}
diff --git a/core/lib/Drupal/Core/DrupalKernel.php b/core/lib/Drupal/Core/DrupalKernel.php
index 3e97607..f6cd799 100644
--- a/core/lib/Drupal/Core/DrupalKernel.php
+++ b/core/lib/Drupal/Core/DrupalKernel.php
@@ -20,7 +20,7 @@
 use Symfony\Component\HttpFoundation\Response;
 use Symfony\Component\HttpKernel\HttpKernelInterface;
 use Symfony\Component\HttpKernel\TerminableInterface;
-use Composer\Autoload\ClassLoader;
+use Drupal\Core\Autoload\ClassLoader;
 
 /**
  * The DrupalKernel class is the core of Drupal itself.
@@ -98,7 +98,7 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
   /**
    * The classloader object.
    *
-   * @var \Composer\Autoload\ClassLoader
+   * @var \Drupal\Core\Autoload\ClassLoader
    */
   protected $classLoader;
 
@@ -151,7 +151,7 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
    *   String indicating the environment, e.g. 'prod' or 'dev'. Used by
    *   Symfony\Component\HttpKernel\Kernel::__construct(). Drupal does not use
    *   this value currently. Pass 'prod'.
-   * @param \Composer\Autoload\ClassLoader $class_loader
+   * @param \Drupal\Core\Autoload\ClassLoader $class_loader
    *   (optional) The classloader is only used if $storage is not given or
    *   the load from storage fails and a container rebuild is required. In
    *   this case, the loaded modules will be registered with this loader in
@@ -219,7 +219,7 @@ public function discoverServiceProviders() {
       $this->moduleList = isset($module_list['enabled']) ? $module_list['enabled'] : array();
     }
     $module_filenames = $this->getModuleFileNames();
-    $this->registerNamespaces($this->getModuleNamespaces($module_filenames));
+    $this->registerNamespacesPsr4($this->getModuleNamespacesPsr4($module_filenames));
 
     // Load each module's serviceProvider class.
     foreach ($this->moduleList as $module => $weight) {
@@ -250,7 +250,6 @@ public function discoverServiceProviders() {
     return $serviceProviders;
   }
 
-
   /**
    * {@inheritdoc}
    */
@@ -404,8 +403,8 @@ protected function initializeContainer() {
       // All namespaces must be registered before we attempt to use any service
       // from the container.
       $container_modules = $this->container->getParameter('container.modules');
-      $namespaces_before = $this->classLoader->getPrefixes();
-      $this->registerNamespaces($this->getModuleNamespaces($container_modules));
+      $namespaces_before = $this->classLoader->getPrefixesPsr4();
+      $this->registerNamespacesPsr4($this->getModuleNamespacesPsr4($container_modules));
 
       // If 'container.modules' is wrong, the container must be rebuilt.
       if (!isset($this->moduleList)) {
@@ -418,9 +417,9 @@ protected function initializeContainer() {
         // registerNamespaces() performs a merge rather than replace, so to
         // effectively remove erroneous registrations, we must replace them with
         // empty arrays.
-        $namespaces_after = $this->classLoader->getPrefixes();
+        $namespaces_after = $this->classLoader->getPrefixesPsr4();
         $namespaces_before += array_fill_keys(array_diff(array_keys($namespaces_after), array_keys($namespaces_before)), array());
-        $this->registerNamespaces($namespaces_before);
+        $this->registerNamespacesPsr4($namespaces_before);
       }
     }
 
@@ -494,14 +493,15 @@ protected function buildContainer() {
     $container->setParameter('container.modules', $this->getModuleFileNames());
 
     // Get a list of namespaces and put it onto the container.
-    $namespaces = $this->getModuleNamespaces($this->getModuleFileNames());
+    $namespaces = $this->getModuleNamespacesPsr4($this->getModuleFileNames());
     // Add all components in \Drupal\Core and \Drupal\Component that have a
     // Plugin directory.
     foreach (array('Core', 'Component') as $parent_directory) {
       $path = DRUPAL_ROOT . '/core/lib/Drupal/' . $parent_directory;
+      $parent_namespace = 'Drupal\\' . $parent_directory;
       foreach (new \DirectoryIterator($path) as $component) {
         if (!$component->isDot() && is_dir($component->getPathname() . '/Plugin')) {
-          $namespaces['Drupal\\' . $parent_directory  .'\\' . $component->getFilename()] = DRUPAL_ROOT . '/core/lib';
+          $namespaces[$parent_namespace . '\\' . $component->getFilename()] = $path . '/' . $component->getFilename();
         }
       }
     }
@@ -623,7 +623,11 @@ protected function storage() {
   }
 
   /**
-   * Returns the file name for each enabled module.
+   * Gets the file name for each enabled module.
+   *
+   * @return array
+   *   Array where each key is a module name, and each value is a path to the
+   *   respective *.module or *.profile file.
    */
   protected function getModuleFileNames() {
     $filenames = array();
@@ -636,18 +640,67 @@ protected function getModuleFileNames() {
   }
 
   /**
-   * Gets the namespaces of each enabled module.
+   * Gets the PSR-4 base directories for module namespaces.
+   *
+   * @param array $module_file_names
+   *   Array where each key is a module name, and each value is a path to the
+   *   respective *.module or *.profile file.
+   *
+   * @return array
+   *   Array where each key is a module namespace like 'Drupal\system', and each
+   *   value is an array of PSR-4 base directories associated with the module
+   *   namespace.
+   */
+  protected function getModuleNamespacesPsr4($module_file_names) {
+    $namespaces = array();
+    foreach ($module_file_names as $module => $filename) {
+      // @todo Remove lib/Drupal/$module, once the switch to PSR-4 is complete.
+      $namespaces["Drupal\\$module"][] = DRUPAL_ROOT . '/' . dirname($filename) . '/lib/Drupal/' . $module;
+      $namespaces["Drupal\\$module"][] = DRUPAL_ROOT . '/' . dirname($filename) . '/lib';
+    }
+    return $namespaces;
+  }
+
+  /**
+   * Gets the PSR-0 base directories for module namespaces.
+   *
+   * @param array $module_file_names
+   *   Array where each key is a module name, and each value is a path to the
+   *   respective *.module or *.profile file.
+   *
+   * @return array
+   *   Array where each key is a module namespace like 'Drupal\system', and each
+   *   value is a PSR-0 base directory associated with the module namespace.
    */
-  protected function getModuleNamespaces($moduleFileNames) {
+  protected function getModuleNamespaces($module_file_names) {
     $namespaces = array();
-    foreach ($moduleFileNames as $module => $filename) {
+    foreach ($module_file_names as $module => $filename) {
       $namespaces["Drupal\\$module"] = DRUPAL_ROOT . '/' . dirname($filename) . '/lib';
     }
     return $namespaces;
   }
 
   /**
-   * Registers a list of namespaces.
+   * Registers a list of namespaces with PSR-4 directories for class loading.
+   *
+   * @param array $namespaces
+   *   Array where each key is a namespace like 'Drupal\system', and each value
+   *   is either a PSR-4 base directory, or an array of PSR-4 base directories
+   *   associated with this namespace.
+   */
+  protected function registerNamespacesPsr4(array $namespaces = array()) {
+    foreach ($namespaces as $prefix => $paths) {
+      $this->classLoader->addPsr4($prefix . '\\', $paths);
+    }
+  }
+
+  /**
+   * Registers a list of namespaces with PSR-0 directories for class loading.
+   *
+   * @param array $namespaces
+   *   Array where each key is a namespace like 'Drupal\system', and each value
+   *   is either a PSR-0 base directory, or an array of PSR-0 base directories
+   *   associated with this namespace.
    */
   protected function registerNamespaces(array $namespaces = array()) {
     foreach ($namespaces as $prefix => $path) {
diff --git a/core/lib/Drupal/Core/Plugin/Discovery/AnnotatedClassDiscovery.php b/core/lib/Drupal/Core/Plugin/Discovery/AnnotatedClassDiscovery.php
index ffafdf6..0192ec3 100644
--- a/core/lib/Drupal/Core/Plugin/Discovery/AnnotatedClassDiscovery.php
+++ b/core/lib/Drupal/Core/Plugin/Discovery/AnnotatedClassDiscovery.php
@@ -15,17 +15,23 @@
 class AnnotatedClassDiscovery extends ComponentAnnotatedClassDiscovery {
 
   /**
-   * The subdirectory within a namespace to look for plugins.
+   * A suffix to append to each PSR-4 directory associated with a base
+   * namespace, to form the directories where plugins are found.
    *
-   * If the plugins are in the top level of the namespace and not within a
-   * subdirectory, set this to an empty string.
+   * @var string
+   */
+  protected $directorySuffix = '';
+
+  /**
+   * A suffix to append to each base namespace, to obtain the namespaces where
+   * plugins are found.
    *
    * @var string
    */
-  protected $subdir = '';
+  protected $namespaceSuffix = '';
 
   /**
-   * An object containing the namespaces to look for plugin implementations.
+   * A list of base namespaces with their PSR-4 directories.
    *
    * @var \Traversable
    */
@@ -47,7 +53,13 @@ class AnnotatedClassDiscovery extends ComponentAnnotatedClassDiscovery {
    */
   function __construct($subdir, \Traversable $root_namespaces, $plugin_definition_annotation_name = 'Drupal\Component\Annotation\Plugin') {
     if ($subdir) {
-      $this->subdir = str_replace('/', '\\', $subdir);
+      // Prepend a directory separator to $subdir,
+      // if it does not already have one.
+      if ('/' !== $subdir[0]) {
+        $subdir = '/' . $subdir;
+      }
+      $this->directorySuffix = $subdir;
+      $this->namespaceSuffix = str_replace('/', '\\', $subdir);
     }
     $this->rootNamespacesIterator = $root_namespaces;
     $plugin_namespaces = array();
@@ -106,11 +118,28 @@ protected function getProviderFromNamespace($namespace) {
    */
   protected function getPluginNamespaces() {
     $plugin_namespaces = array();
-    foreach ($this->rootNamespacesIterator as $namespace => $dir) {
-      if ($this->subdir) {
-        $namespace .= "\\{$this->subdir}";
+    if ($this->namespaceSuffix) {
+      foreach ($this->rootNamespacesIterator as $namespace => $dirs) {
+        // Append the namespace suffix to the base namespace, to obtain the
+        // plugin namespace. E.g. 'Drupal\Views' may become
+        // 'Drupal\Views\Plugin\Block'.
+        $namespace .= $this->namespaceSuffix;
+        foreach ((array) $dirs as $dir) {
+          // Append the directory suffix to the PSR-4 base directory, to obtain
+          // the directory where plugins are found.
+          // E.g. DRUPAL_CORE . 'core/modules/views/lib' may become
+          // DRUPAL_CORE . 'core/modules/views/lib/Plugin/Block'.
+          $plugin_namespaces[$namespace][] = $dir . $this->directorySuffix;
+        }
+      }
+    }
+    else {
+      // Both the namespace suffix and the directory suffix are empty,
+      // so the plugin namespaces and directories are the same as the base
+      // directories.
+      foreach ($this->rootNamespacesIterator as $namespace => $dirs) {
+        $plugin_namespaces[$namespace] = (array) $dirs;
       }
-      $plugin_namespaces[$namespace] = array($dir);
     }
 
     return $plugin_namespaces;
diff --git a/core/modules/simpletest/simpletest.module b/core/modules/simpletest/simpletest.module
index da7c265..0f5d433 100644
--- a/core/modules/simpletest/simpletest.module
+++ b/core/modules/simpletest/simpletest.module
@@ -454,21 +454,26 @@ function simpletest_test_get_all() {
       $all_data = $module_data + system_rebuild_theme_data();
       $all_data += drupal_system_listing('/\.profile$/', 'profiles', 'name');
       foreach ($all_data as $name => $data) {
-        // Build directory in which the test files would reside.
-        $tests_dir = DRUPAL_ROOT . '/' . dirname($data->uri) . '/lib/Drupal/' . $name . '/Tests';
+        $extension_dir = DRUPAL_ROOT . '/' . dirname($data->uri);
+
+        // Build directories in which the test files would reside.
+        $tests_dirs = array(
+          $extension_dir . '/lib/Drupal/' . $name . '/Tests',
+          $extension_dir . '/lib/Tests',
+        );
+
+        $namespace = 'Drupal\\' . $name . '\Tests\\';
+
         // Scan it for test files if it exists.
-        if (is_dir($tests_dir)) {
-          $files = file_scan_directory($tests_dir, '/.*\.php/');
-          if (!empty($files)) {
-            $basedir = DRUPAL_ROOT . '/' . dirname($data->uri) . '/lib/';
-            foreach ($files as $file) {
-              // Convert the file name into the namespaced class name.
-              $replacements = array(
-                '/' => '\\',
-                $basedir => '',
-                '.php' => '',
-              );
-              $classes[] = strtr($file->uri, $replacements);
+        foreach ($tests_dirs as $tests_dir) {
+          if (is_dir($tests_dir)) {
+            $files = file_scan_directory($tests_dir, '/.*\.php/');
+            if (!empty($files)) {
+              $strlen = strlen($tests_dir) + 1;
+              // Convert the file names into the namespaced class names.
+              foreach ($files as $file) {
+                $classes[] = $namespace . str_replace('/', '\\', substr($file->uri, $strlen, -4));
+              }
             }
           }
         }
diff --git a/core/modules/system/lib/Drupal/system/Tests/Plugin/Discovery/AnnotatedClassDiscoveryTest.php b/core/modules/system/lib/Drupal/system/Tests/Plugin/Discovery/AnnotatedClassDiscoveryTest.php
index d2fba9b..52bd303 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Plugin/Discovery/AnnotatedClassDiscoveryTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Plugin/Discovery/AnnotatedClassDiscoveryTest.php
@@ -57,7 +57,13 @@ public function setUp() {
         'provider' => 'plugin_test',
       ),
     );
-    $namespaces = new \ArrayObject(array('Drupal\plugin_test' => DRUPAL_ROOT . '/core/modules/system/tests/modules/plugin_test/lib'));
+    $namespaces = new \ArrayObject(array(
+      'Drupal\plugin_test' => array(
+        // @todo Remove lib/Drupal/$module, once the switch to PSR-4 is complete.
+        DRUPAL_ROOT . '/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test',
+        DRUPAL_ROOT . '/core/modules/system/tests/modules/plugin_test/lib',
+      ),
+    ));
     $this->discovery = new AnnotatedClassDiscovery('Plugin/plugin_test/fruit', $namespaces);
     $this->emptyDiscovery = new AnnotatedClassDiscovery('Plugin/non_existing_module/non_existing_plugin_type', $namespaces);
   }
diff --git a/core/modules/system/lib/Drupal/system/Tests/Plugin/Discovery/CustomAnnotationClassDiscoveryTest.php b/core/modules/system/lib/Drupal/system/Tests/Plugin/Discovery/CustomAnnotationClassDiscoveryTest.php
index d61c013..17bbfa5 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Plugin/Discovery/CustomAnnotationClassDiscoveryTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Plugin/Discovery/CustomAnnotationClassDiscoveryTest.php
@@ -41,7 +41,13 @@ protected function setUp() {
         'provider' => 'plugin_test',
       ),
     );
-    $root_namespaces = new \ArrayObject(array('Drupal\plugin_test' => DRUPAL_ROOT . '/core/modules/system/tests/modules/plugin_test/lib'));
+    $root_namespaces = new \ArrayObject(array(
+      'Drupal\plugin_test' => array(
+        // @todo Remove lib/Drupal/$module, once the switch to PSR-4 is complete.
+        DRUPAL_ROOT . '/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test',
+        DRUPAL_ROOT . '/core/modules/system/tests/modules/plugin_test/lib',
+      ),
+    ));
 
     $this->discovery = new AnnotatedClassDiscovery('Plugin/plugin_test/custom_annotation', $root_namespaces, 'Drupal\plugin_test\Plugin\Annotation\PluginExample');
     $this->emptyDiscovery = new AnnotatedClassDiscovery('Plugin/non_existing_module/non_existing_plugin_type', $root_namespaces, 'Drupal\plugin_test\Plugin\Annotation\PluginExample');
diff --git a/core/modules/system/lib/Drupal/system/Tests/Plugin/Discovery/CustomDirectoryAnnotatedClassDiscoveryTest.php b/core/modules/system/lib/Drupal/system/Tests/Plugin/Discovery/CustomDirectoryAnnotatedClassDiscoveryTest.php
index c005300..b817c68 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Plugin/Discovery/CustomDirectoryAnnotatedClassDiscoveryTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Plugin/Discovery/CustomDirectoryAnnotatedClassDiscoveryTest.php
@@ -39,7 +39,13 @@ protected function setUp() {
         'provider' => 'plugin_test',
       ),
     );
-    $namespaces = new \ArrayObject(array('Drupal\plugin_test' => DRUPAL_ROOT . '/core/modules/system/tests/modules/plugin_test/lib'));
+    $namespaces = new \ArrayObject(array(
+      'Drupal\plugin_test' => array(
+        // @todo Remove lib/Drupal/$module, once the switch to PSR-4 is complete.
+        DRUPAL_ROOT . '/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test',
+        DRUPAL_ROOT . '/core/modules/system/tests/modules/plugin_test/lib',
+      ),
+    ));
     $this->discovery = new AnnotatedClassDiscovery('', $namespaces);
     $empty_namespaces = new \ArrayObject();
     $this->emptyDiscovery = new AnnotatedClassDiscovery('', $empty_namespaces);
diff --git a/core/phpunit.xml.dist b/core/phpunit.xml.dist
index 35ff254..5d4aec5 100644
--- a/core/phpunit.xml.dist
+++ b/core/phpunit.xml.dist
@@ -12,7 +12,7 @@
       <!-- Exclude Drush tests. -->
       <exclude>./drush/tests</exclude>
       <!-- Exclude special-case files from config's test modules. -->
-      <exclude>./modules/config/tests/config_test/lib/Drupal/config_test</exclude>
+      <exclude>./modules/config/tests/config_test/lib</exclude>
     </testsuite>
   </testsuites>
   <!-- Filter for coverage reports. -->
diff --git a/core/scripts/switch-psr4.sh b/core/scripts/switch-psr4.sh
new file mode 100644
index 0000000..b38f80c
--- /dev/null
+++ b/core/scripts/switch-psr4.sh
@@ -0,0 +1,107 @@
+#!/bin/php
+<?php
+
+/**
+ * @file
+ * Moves class files in extensions to their PSR-4 location.
+ */
+
+// Determine DRUPAL_ROOT.
+$dir = dirname(__FILE__);
+while (!defined('DRUPAL_ROOT')) {
+  if (is_dir($dir . '/core')) {
+    define('DRUPAL_ROOT', $dir);
+  }
+  $dir = dirname($dir);
+}
+
+process_extensions_base_dir(DRUPAL_ROOT . '/core/modules');
+process_extensions_base_dir(DRUPAL_ROOT . '/core/profiles');
+
+function process_extensions_base_dir($dir) {
+  /**
+   * @var SplFileInfo $fileinfo
+   */
+  foreach (new \DirectoryIterator($dir) as $fileinfo) {
+    if ($fileinfo->isDot()) {
+      // do nothing
+    }
+    elseif ($fileinfo->isDir()) {
+      process_candidate_dir($fileinfo->getPathname());
+    }
+  }
+}
+
+function process_candidate_dir($dir) {
+  foreach (new \DirectoryIterator($dir) as $fileinfo) {
+    if ($fileinfo->isDot()) {
+      // Ignore "." and "..".
+    }
+    elseif ($fileinfo->isDir()) {
+      // It's a directory.
+      switch ($fileinfo->getFilename()) {
+        case 'lib':
+          // Ignore these directory names.
+          continue;
+        default:
+          // Look for more extensions in subdirectories.
+          process_candidate_dir($fileinfo->getPathname());
+      }
+    }
+    else {
+      // It's a file.
+      if (preg_match('/^(.+).info.yml$/', $fileinfo->getFilename(), $m)) {
+        // It's a *.info.yml file, so we found an extension directory.
+        $extension_name = $m[1];
+      }
+    }
+  }
+  if (isset($extension_name)) {
+    process_extension($extension_name, $dir);
+  }
+}
+
+function process_extension($name, $dir) {
+
+  // Move main module class files.
+  if (is_dir("$dir/lib/Drupal/$name")) {
+    // This is a module directory with a PSR-0 /lib/ folder.
+    // Move to src/ as a temporary location.
+    if (!rename($src = "$dir/lib/Drupal/$name", $dest = "$dir/src")) {
+      throw new Exception("Rename $src to $dest failed.");
+    }
+  }
+
+  // Clean up empty directories.
+  foreach (array(
+    "lib/Drupal/$name",
+    'lib/Drupal',
+    'lib',
+  ) as $subdir) {
+    if (!is_dir("$dir/$subdir")) {
+      continue;
+    }
+    if (!is_dir_empty("$dir/$subdir")) {
+      throw new Exception("$dir/$subdir is not empty.");
+    }
+    rmdir("$dir/$subdir");
+  }
+
+  // Move back to lib/.
+  if (is_dir("$dir/src")) {
+    rename("$dir/src", "$dir/lib");
+  }
+}
+
+function is_dir_empty($dir) {
+  if (!is_readable($dir)) {
+    return NULL;
+  }
+  $handle = opendir($dir);
+  while (false !== ($entry = readdir($handle))) {
+    if ($entry != "." && $entry != "..") {
+      return FALSE;
+    }
+  }
+  return TRUE;
+}
diff --git a/core/tests/bootstrap.php b/core/tests/bootstrap.php
index c69a52f..23d6116 100644
--- a/core/tests/bootstrap.php
+++ b/core/tests/bootstrap.php
@@ -59,6 +59,7 @@ function drupal_phpunit_register_extension_dirs(Composer\Autoload\ClassLoader $l
     $lib_path = $dir . '/lib';
     if (is_dir($lib_path)) {
       $loader->add('Drupal\\' . $extension, $lib_path);
+      $loader->addPsr4('Drupal\\' . $extension, $lib_path);
     }
     $tests_path = $dir . '/tests';
     if (is_dir($tests_path)) {
diff --git a/core/vendor/autoload.php b/core/vendor/autoload.php
index e934391..e665445 100644
--- a/core/vendor/autoload.php
+++ b/core/vendor/autoload.php
@@ -1,7 +1,23 @@
 <?php
 
-// autoload.php @generated by Composer
+/**
+ * @file
+ * Drupal-specific autoload.php to be copied to replace core/vendor/autoload.php
+ * generated by Composer.
+ *
+ * Having a Drupal-specific autoload.php makes it easier to use a ClassLoader
+ * implementation different from the one provided by Composer.
+ *
+ * The file will be copied to replace core/vendor/autoload.php, by a script
+ * triggered after composer autoload-dump. That script is in
+ * Drupal\Core\Autoload\GeneratorScript::postAutoloadDump().
+ *
+ * This means, the official autoload.php to include in scripts will always be
+ * core/vendor/autoload.php.
+ */
 
-require_once __DIR__ . '/composer' . '/autoload_real.php';
+use Drupal\Core\Autoload\DrupalAutoloaderInit;
 
-return ComposerAutoloaderInitdcdeef3a2347836a4b3309cb54064cf9::getLoader();
+require_once dirname(__DIR__) . '/lib/Drupal/Core/Autoload/DrupalAutoloaderInit.php';
+
+return DrupalAutoloaderInit::getLoader();
