diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index 74af7c6..23d0840 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -10,7 +10,8 @@
 use Drupal\Core\DrupalKernel;
 use Drupal\Core\Database\Database;
 use Drupal\Core\DependencyInjection\ContainerBuilder;
-use Symfony\Component\ClassLoader\ClassLoader;
+use Drupal\Core\ClassLoader\ClassLoaderInterface;
+use Drupal\Core\ClassLoader\ClassLoader;
 use Symfony\Component\ClassLoader\ApcClassLoader;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\DependencyInjection\Container;
@@ -2750,64 +2751,72 @@ function arg($index = NULL, $path = NULL) {
  * classes, interfaces, and traits (PHP 5.4 and later). It's only dependency
  * is DRUPAL_ROOT. Otherwise it may be called as early as possible.
  *
- * @param $class_loader
+ * @param string $loader_name
  *   The name of class loader to use. This can be used to change the class
  *   loader class when calling drupal_classloader() from settings.php. It is
  *   ignored otherwise.
- *
- * @return \Symfony\Component\ClassLoader\ClassLoader
+ * @param ClassLoaderInterface $custom_loader
+ *   Loader object.
+ *   This can be called from settings.php to replace the class loader.
+ * @param boolean $add_composer_dir
+ *   Whether to register core and vendor namespaces from composer's
+ *   autoload_classes.php and autoload_namespaces.php. This can be set to FALSE,
+ *   if the namespaces are already registered in the $custom_loader object.
+ *
+ * @throws Exception
+ * @return ClassLoaderInterface
  *   A ClassLoader class instance (or extension thereof).
  */
-function drupal_classloader($class_loader = NULL) {
+function drupal_classloader($loader_name = NULL, ClassLoaderInterface $custom_loader = NULL, $add_composer_dir = TRUE) {
   // By default, use the ClassLoader which is best for development, as it does
   // not break when code is moved on the file system. However, as it is slow,
   // allow to use the APC class loader in production.
   static $loader;
 
   if (!isset($loader)) {
-
-    // Include the Symfony ClassLoader for loading PSR-0-compatible classes.
-    require_once DRUPAL_ROOT . '/core/vendor/symfony/class-loader/Symfony/Component/ClassLoader/ClassLoader.php';
-    $loader = new ClassLoader();
-
-    // Register the class loader.
-    // When configured to use APC, the ApcClassLoader is registered instead.
-    // Note that ApcClassLoader decorates ClassLoader and only provides the
-    // findFile() method, but none of the others. The actual registry is still
-    // in ClassLoader.
-    if (!isset($class_loader)) {
-      $class_loader = settings()->get('class_loader', 'default');
-    }
-    if ($class_loader === 'apc') {
-      require_once DRUPAL_ROOT . '/core/vendor/symfony/class-loader/Symfony/Component/ClassLoader/ApcClassLoader.php';
-      $apc_loader = new ApcClassLoader('drupal.' . drupal_get_hash_salt(), $loader);
-      $apc_loader->register();
+    if (isset($custom_loader)) {
+      // Use a custom loader.
+      $loader = $custom_loader;
+      // Do not call ->register() on the custom loader, to support custom
+      // decorators.
     }
     else {
-      $loader->register();
-    }
+      // Include the Drupal ClassLoader for loading PSR-0-compatible classes.
+      require_once DRUPAL_ROOT . '/core/lib/Drupal/Core/ClassLoader/ClassLoaderInterface.php';
+      require_once DRUPAL_ROOT . '/core/lib/Drupal/Core/ClassLoader/AbstractClassLoader.php';
+      require_once DRUPAL_ROOT . '/core/lib/Drupal/Core/ClassLoader/ClassLoader.php';
+      $loader = new ClassLoader();
+
+      // Determine whether to use a cache decorator for the loader.
+      if (!isset($loader_name)) {
+        $loader_name = settings()->get('class_loader', 'default');
+      }
 
-    // Register namespaces for vendor libraries managed by Composer.
-    $prefixes_and_namespaces = require DRUPAL_ROOT . '/core/vendor/composer/autoload_namespaces.php';
-    $loader->addPrefixes($prefixes_and_namespaces);
+      // Register either the decorator, or the loader itself.
+      if ($loader_name === 'apc') {
+        // Create the APC decorator, and register its loadClass() method on the
+        // spl autoload stack.
+        require_once DRUPAL_ROOT . '/core/vendor/symfony/class-loader/Symfony/Component/ClassLoader/ApcClassLoader.php';
+        $apc_loader = new ApcClassLoader('drupal.' . drupal_get_hash_salt(), $loader);
+        $apc_loader->register();
+      }
+      else {
+        // Register the undecorated class loader.
+        $loader->register();
+      }
+    }
 
-    // Register the loader with PHP.
-    $loader->register();
+    if ($add_composer_dir) {
+      // Register namespaces for vendor libraries managed by Composer.
+      // This always happens on the loader itself, not on the APC decorator.
+      $loader->composerVendorDir(DRUPAL_ROOT . '/core/vendor', FALSE);
+    }
+  }
+  elseif ($custom_loader) {
+    throw new \Exception('Custom loader cannot be set, if a loader already exists.');
   }
-  return $loader;
-}
 
-/**
- * Registers an additional namespace.
- *
- * @param string $name
- *   The namespace component to register; e.g., 'node'.
- * @param string $path
- *   The relative path to the Drupal component in the filesystem.
- */
-function drupal_classloader_register($name, $path) {
-  $loader = drupal_classloader();
-  $loader->addPrefix('Drupal\\' . $name, DRUPAL_ROOT . '/' . $path . '/lib');
+  return $loader;
 }
 
 /**
diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc
index 5217e37..7a14084 100644
--- a/core/includes/install.core.inc
+++ b/core/includes/install.core.inc
@@ -951,7 +951,15 @@ function install_display_output($output, $install_state) {
     $active_task = $install_state['installation_finished'] ? NULL : $install_state['active_task'];
     drupal_add_region_content('sidebar_first', theme('task_list', array('items' => install_tasks_to_display($install_state), 'active' => $active_task, 'variant' => 'install')));
   }
-  print theme('install_page', array('content' => $output));
+  if (function_exists('theme')) {
+    print theme('install_page', array('content' => $output));
+  }
+  elseif (is_string($output)) {
+    print $output;
+  }
+  else {
+    var_dump($output);
+  }
   exit;
 }
 
diff --git a/core/includes/module.inc b/core/includes/module.inc
index cdd3ddd..1214f01 100644
--- a/core/includes/module.inc
+++ b/core/includes/module.inc
@@ -135,7 +135,7 @@ function system_list_reset() {
  */
 function system_register($type, $name, $uri) {
   drupal_get_filename($type, $name, $uri);
-  drupal_classloader_register($name, dirname($uri));
+  drupal_classloader()->addDrupalExtension($name, dirname($uri));
 }
 
 /**
diff --git a/core/lib/Drupal/Core/ClassLoader/AbstractClassLoader.php b/core/lib/Drupal/Core/ClassLoader/AbstractClassLoader.php
new file mode 100644
index 0000000..2ca717c
--- /dev/null
+++ b/core/lib/Drupal/Core/ClassLoader/AbstractClassLoader.php
@@ -0,0 +1,115 @@
+<?php
+
+namespace Drupal\Core\ClassLoader;
+
+
+abstract class AbstractClassLoader implements ClassLoaderInterface {
+
+  protected $useIncludePath = false;
+  protected $classMap = array();
+
+  public function getClassMap() {
+    return $this->classMap;
+  }
+
+  /**
+   * @param array $classMap Class to filename map
+   */
+  public function addClassMap(array $classMap) {
+    if ($this->classMap) {
+      $this->classMap = array_merge($this->classMap, $classMap);
+    } else {
+      $this->classMap = $classMap;
+    }
+  }
+
+  public function addMultiple($prefixes, $prepend = FALSE) {
+    foreach ($prefixes as $prefix => $paths) {
+      $this->add($prefix, $paths, $prepend);
+    }
+  }
+
+  public function composerVendorDir($dir, $complete = TRUE) {
+    if ($complete) {
+      // This does not also register classmap and namespaces,
+      // but also set include paths, and include some files by default.
+      /**
+       * @var \Composer\Autoload\ClassLoader $composerLoader
+       */
+      $composerLoader = $dir . '/autoload.php';
+      $this->add('', $composerLoader->getFallbackDirs());
+      $this->setUseIncludePath($composerLoader->getUseIncludePath());
+      $prefixes = $composerLoader->getPrefixes();
+      $classMap = $composerLoader->getClassMap();
+    }
+    else {
+      $prefixes = require $dir . '/composer/autoload_namespaces.php';
+      $classMap = require $dir . '/composer/autoload_classmap.php';
+    }
+    foreach ($prefixes as $prefix => $path) {
+      $this->add($prefix, $path);
+    }
+    if ($classMap) {
+      $this->addClassMap($classMap);
+    }
+  }
+
+  /**
+   * @inheritdoc
+   */
+  public function addDrupalExtensionsByRelativeFilePath($extensions, $prepend = FALSE) {
+    foreach ($extensions as $extension_name => $relativeFilePath) {
+      $this->addDrupalExtension($extension_name, dirname($relativeFilePath), $prepend);
+    }
+  }
+
+  /**
+   * 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 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;
+    }
+  }
+}
\ No newline at end of file
diff --git a/core/lib/Drupal/Core/ClassLoader/ClassLoader.php b/core/lib/Drupal/Core/ClassLoader/ClassLoader.php
new file mode 100644
index 0000000..973ba1d
--- /dev/null
+++ b/core/lib/Drupal/Core/ClassLoader/ClassLoader.php
@@ -0,0 +1,130 @@
+<?php
+
+namespace Drupal\Core\ClassLoader;
+
+
+class ClassLoader extends AbstractClassLoader {
+
+  private $prefixes = array();
+  private $fallbackDirs = array();
+
+  /**
+   * Registers a set of classes, merging with any others previously set.
+   *
+   * @param string       $prefix  The classes prefix
+   * @param array|string $paths   The location(s) of the classes
+   * @param bool         $prepend Prepend the location(s)
+   */
+  public function add($prefix, $paths, $prepend = false) {
+    if (!$prefix) {
+      if ($prepend) {
+        $this->fallbackDirs = array_merge(
+          (array) $paths,
+          $this->fallbackDirs
+        );
+      } else {
+        $this->fallbackDirs = array_merge(
+          $this->fallbackDirs,
+          (array) $paths
+        );
+      }
+
+      return;
+    }
+
+    $first = $prefix[0];
+    if (!isset($this->prefixes[$first][$prefix])) {
+      $this->prefixes[$first][$prefix] = (array) $paths;
+
+      return;
+    }
+    if ($prepend) {
+      $this->prefixes[$first][$prefix] = array_merge(
+        (array) $paths,
+        $this->prefixes[$first][$prefix]
+      );
+    } else {
+      $this->prefixes[$first][$prefix] = array_merge(
+        $this->prefixes[$first][$prefix],
+        (array) $paths
+      );
+    }
+  }
+
+  /**
+   * @param $extensionName
+   * @param $relativeExtensionDir
+   * @param bool $prepend
+   */
+  public function addDrupalExtension($extensionName, $relativeExtensionDir, $prepend = false) {
+    $this->add('Drupal\\' . $extensionName . '\\',
+      DRUPAL_ROOT . DIRECTORY_SEPARATOR . $relativeExtensionDir . '/lib',
+      $prepend);
+  }
+
+  /**
+   * @param $extensionName
+   * @param $relativeExtensionDir
+   * @param bool $prepend
+   */
+  public function addDrupalExtensionTests($extensionName, $relativeExtensionDir, $prepend = false) {
+    $this->add('Drupal\\' . $extensionName . '\Tests\\',
+      DRUPAL_ROOT . DIRECTORY_SEPARATOR . $relativeExtensionDir . '/tests',
+      $prepend);
+  }
+
+  /**
+   * 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);
+    }
+
+    if (isset($this->classMap[$class])) {
+      return $this->classMap[$class];
+    }
+
+    if (false !== $pos = strrpos($class, '\\')) {
+      // namespaced class name
+      $classPath = strtr(substr($class, 0, $pos), '\\', DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
+      $className = substr($class, $pos + 1);
+    } else {
+      // PEAR-like class name
+      $classPath = null;
+      $className = $class;
+    }
+
+    $classPath .= strtr($className, '_', DIRECTORY_SEPARATOR) . '.php';
+
+    $first = $class[0];
+    if (isset($this->prefixes[$first])) {
+      foreach ($this->prefixes[$first] as $prefix => $dirs) {
+        if (0 === strpos($class, $prefix)) {
+          foreach ($dirs as $dir) {
+            if (file_exists($dir . DIRECTORY_SEPARATOR . $classPath)) {
+              return $dir . DIRECTORY_SEPARATOR . $classPath;
+            }
+          }
+        }
+      }
+    }
+
+    foreach ($this->fallbackDirs as $dir) {
+      if (file_exists($dir . DIRECTORY_SEPARATOR . $classPath)) {
+        return $dir . DIRECTORY_SEPARATOR . $classPath;
+      }
+    }
+
+    if ($this->useIncludePath && $file = stream_resolve_include_path($classPath)) {
+      return $file;
+    }
+
+    return $this->classMap[$class] = false;
+  }
+}
\ No newline at end of file
diff --git a/core/lib/Drupal/Core/ClassLoader/ClassLoaderInterface.php b/core/lib/Drupal/Core/ClassLoader/ClassLoaderInterface.php
new file mode 100644
index 0000000..cdfdb3a
--- /dev/null
+++ b/core/lib/Drupal/Core/ClassLoader/ClassLoaderInterface.php
@@ -0,0 +1,87 @@
+<?php
+
+namespace Drupal\Core\ClassLoader;
+
+
+interface ClassLoaderInterface {
+
+  public function getClassMap();
+
+  /**
+   * @param array $classMap Class to filename map
+   */
+  public function addClassMap(array $classMap);
+
+  /**
+   * Registers a set of classes, merging with any others previously set.
+   *
+   * @param string       $prefix  The classes prefix
+   * @param array|string $paths   The location(s) of the classes
+   * @param bool         $prepend Prepend the location(s)
+   */
+  public function add($prefix, $paths, $prepend = false);
+
+  public function addMultiple($prefixes, $prepend = false);
+
+  public function composerVendorDir($dir);
+
+  /**
+   * @param $extensionName
+   * @param $relativeExtensionDir
+   * @param bool $prepend
+   */
+  public function addDrupalExtension($extensionName, $relativeExtensionDir, $prepend = FALSE);
+
+  /**
+   * @param $extensionName
+   * @param $relativeExtensionDir
+   * @param bool $prepend
+   */
+  public function addDrupalExtensionTests($extensionName, $relativeExtensionDir, $prepend = false);
+
+  /**
+   * @param array $extensions
+   * @param bool $prepend
+   */
+  public function addDrupalExtensionsByRelativeFilePath($extensions, $prepend = FALSE);
+
+  /**
+   * Turns on searching the include path for class files.
+   *
+   * @param bool $useIncludePath
+   */
+  public function setUseIncludePath($useIncludePath);
+
+  /**
+   * Can be used to check if the autoloader uses the include path to check
+   * for classes.
+   *
+   * @return bool
+   */
+  public function getUseIncludePath();
+
+  /**
+   * Registers this instance as an autoloader.
+   *
+   * @param bool $prepend Whether to prepend the autoloader or not
+   */
+  public function register($prepend = false);
+
+  /**
+   * Unregisters this instance as an autoloader.
+   */
+  public function unregister();
+
+  /**
+   * Loads the given class or interface.
+   *
+   * @param string $class
+   *   The name of the class
+   * @return bool
+   *   FALSE, if not found.
+   *   TRUE, if loaded and $returnFile was FALSE.
+   */
+  public function loadClass($class);
+
+  public function findFile($class);
+}
\ No newline at end of file
diff --git a/core/lib/Drupal/Core/DrupalKernel.php b/core/lib/Drupal/Core/DrupalKernel.php
index af1fe52..a8eb0bf 100644
--- a/core/lib/Drupal/Core/DrupalKernel.php
+++ b/core/lib/Drupal/Core/DrupalKernel.php
@@ -12,7 +12,7 @@
 use Drupal\Core\CoreServiceProvider;
 use Drupal\Core\DependencyInjection\ContainerBuilder;
 use Drupal\Core\DependencyInjection\YamlFileLoader;
-use Symfony\Component\ClassLoader\ClassLoader;
+use Drupal\Core\ClassLoader\ClassLoaderInterface;
 use Symfony\Component\Config\Loader\LoaderInterface;
 use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
 use Symfony\Component\DependencyInjection\Dumper\PhpDumper;
@@ -97,7 +97,7 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
   /**
    * The classloader object.
    *
-   * @var \Symfony\Component\ClassLoader\ClassLoader
+   * @var ClassLoaderInterface
    */
   protected $classLoader;
 
@@ -150,7 +150,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 \Symfony\Component\ClassLoader\ClassLoader $class_loader
+   * @param ClassLoaderInterface $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
@@ -159,7 +159,7 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
    *   (optional) FALSE to stop the container from being written to or read
    *   from disk. Defaults to TRUE.
    */
-  public function __construct($environment, ClassLoader $class_loader, $allow_dumping = TRUE) {
+  public function __construct($environment, ClassLoaderInterface $class_loader, $allow_dumping = TRUE) {
     $this->environment = $environment;
     $this->booted = false;
     $this->classLoader = $class_loader;
@@ -233,7 +233,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->classLoader->addDrupalExtensionsByRelativeFilePath($module_filenames);
 
     // Load each module's serviceProvider class.
     foreach ($this->moduleList as $module => $weight) {
@@ -417,8 +417,7 @@ 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));
+      $this->classLoader->addDrupalExtensionsByRelativeFilePath($container_modules);
 
       // If 'container.modules' is wrong, the container must be rebuilt.
       if (!isset($this->moduleList)) {
@@ -427,13 +426,21 @@ protected function initializeContainer() {
       if (array_keys($this->moduleList) !== array_keys($container_modules)) {
         $persist = $this->getServicesToPersist();
         unset($this->container);
-        // Revert the class loader to its prior state. However,
-        // 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_before += array_fill_keys(array_diff(array_keys($namespaces_after), array_keys($namespaces_before)), array());
-        $this->registerNamespaces($namespaces_before);
+        // @todo Revert the class loader?
+        //   At this point, previous versions did attempt to revert the
+        //   class loader to its previous state, with the intention to remove
+        //   erroneous registrations.
+        //   However, we can assume that this did not work, because
+        //   \Symfony\Component\ClassLoader\ClassLoader does not support removal
+        //   of registered namespaces, it only allows adding them.
+        //   The other question is, whether removal of namespace registrations
+        //   is desirable in the first place. Some of the classes might already
+        //   be included, and removal of the namespace cannot undo that.
+        //   A more interesting case is if a module has moved to a different
+        //   directory. This case is not even detected in the if() clause above.
+        //
+        //   Conclusion: A revert mechanic can be added, but needs to be
+        //   discussed first.
       }
     }
 
@@ -521,7 +528,7 @@ protected function buildContainer() {
     $container->setParameter('container.namespaces', $namespaces);
 
     // Register synthetic services.
-    $container->register('class_loader', 'Symfony\Component\ClassLoader\ClassLoader')->setSynthetic(TRUE);
+    $container->register('class_loader', 'Drupal\Core\ClassLoader\ClassLoaderInterface')->setSynthetic(TRUE);
     $container->register('kernel', 'Symfony\Component\HttpKernel\KernelInterface')->setSynthetic(TRUE);
     $container->register('service_container', 'Symfony\Component\DependencyInjection\ContainerInterface')->setSynthetic(TRUE);
     $yaml_loader = new YamlFileLoader($container);
@@ -656,11 +663,4 @@ protected function getModuleNamespaces($moduleFileNames) {
     }
     return $namespaces;
   }
-
-  /**
-   * Registers a list of namespaces.
-   */
-  protected function registerNamespaces(array $namespaces = array()) {
-    $this->classLoader->addPrefixes($namespaces);
-  }
 }
diff --git a/core/lib/Drupal/Core/Extension/UpdateModuleHandler.php b/core/lib/Drupal/Core/Extension/UpdateModuleHandler.php
index 0e5a57b..04c76dc 100644
--- a/core/lib/Drupal/Core/Extension/UpdateModuleHandler.php
+++ b/core/lib/Drupal/Core/Extension/UpdateModuleHandler.php
@@ -125,7 +125,7 @@ public function enable($module_list, $enable_dependencies = TRUE) {
       system_list_reset();
       $this->moduleList[$module] = drupal_get_filename('module', $module);
       $this->load($module);
-      drupal_classloader_register($module, dirname($this->moduleList[$module]));
+      drupal_classloader()->addDrupalExtension($module, dirname($this->moduleList[$module]));
       // @todo Figure out what to do about hook_install() and hook_enable().
     }
     return $old_schema;
diff --git a/core/modules/simpletest/simpletest.module b/core/modules/simpletest/simpletest.module
index 587b6c0..1beb719 100644
--- a/core/modules/simpletest/simpletest.module
+++ b/core/modules/simpletest/simpletest.module
@@ -1,5 +1,6 @@
 <?php
 
+use Drupal\Core\ClassLoader\ClassLoaderInterface;
 use Drupal\Core\Database\Database;
 use Drupal\simpletest\TestBase;
 use Symfony\Component\Process\PhpExecutableFinder;
@@ -520,27 +521,19 @@ function simpletest_classloader_register() {
     'theme' => array('dir' => 'themes', 'extension' => 'info'),
     'profile' => array('dir' => 'profiles', 'extension' => 'profile'),
   );
+  $loader = drupal_classloader();
   foreach ($types as $type => $info) {
     $matches = drupal_system_listing('/^' . DRUPAL_PHP_FUNCTION_PATTERN . '\.' . $info['extension'] . '$/', $info['dir']);
     foreach ($matches as $name => $file) {
-      drupal_classloader_register($name, dirname($file->uri));
-      drupal_classloader()->addPrefix('Drupal\\' . $name . '\\Tests', DRUPAL_ROOT . '/' . dirname($file->uri) . '/tests');
+      $loader->addDrupalExtension($name, dirname($file->uri));
+      $loader->addDrupalExtensionTests($name, dirname($file->uri));
       // While being there, prime drupal_get_filename().
       drupal_get_filename($type, $name, $file->uri);
     }
   }
 
   // Register the core test directory so we can find \Drupal\UnitTestCase.
-  drupal_classloader()->addPrefix('Drupal\\Tests', DRUPAL_ROOT . '/core/tests');
-
-  // Manually register phpunit prefixes because they use a classmap instead of a
-  // prefix. This can be safely removed if we move to using composer's
-  // autoloader with a classmap.
-  drupal_classloader()->addPrefixes(array(
-    'PHPUnit' => DRUPAL_ROOT . '/core/vendor/phpunit/phpunit',
-    'File_Iterator' => DRUPAL_ROOT . '/core/vendor/phpunit/php-file-iterator/',
-    'PHP_Timer' => DRUPAL_ROOT . '/core/vendor/phpunit/php-timer/',
-  ));
+  $loader->add('Drupal\\Tests\\', DRUPAL_ROOT . '/core/tests');
 }
 
 /**
diff --git a/core/modules/system/lib/Drupal/system/Tests/DrupalKernel/DrupalKernelTest.php b/core/modules/system/lib/Drupal/system/Tests/DrupalKernel/DrupalKernelTest.php
index db60d18..60851d6 100644
--- a/core/modules/system/lib/Drupal/system/Tests/DrupalKernel/DrupalKernelTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/DrupalKernel/DrupalKernelTest.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\system\Tests\DrupalKernel;
 
+use Drupal\Core\ClassLoader\ClassLoaderInterface;
 use Drupal\Core\DrupalKernel;
 use Drupal\Component\PhpStorage\MTimeProtectedFastFileStorage;
 use Drupal\Component\PhpStorage\FileReadOnlyStorage;
@@ -79,8 +80,7 @@ function testCompileDIC() {
     $this->assertTrue($is_compiled_container);
     // Test that our synthetic services are there.
     $classloader = $container->get('class_loader');
-    $refClass = new ReflectionClass($classloader);
-    $this->assertTrue($refClass->hasMethod('loadClass'), 'Container has a classloader');
+    $this->assertTrue($classloader instanceof ClassLoaderInterface, 'Container has a classloader');
 
     // We make this assertion here purely to show that the new container below
     // is functioning correctly, i.e. we get a brand new ContainerBuilder
@@ -107,8 +107,7 @@ function testCompileDIC() {
     $this->assertTrue($container->has('service_provider_test_class'));
     // Test that our synthetic services are there.
     $classloader = $container->get('class_loader');
-    $refClass = new ReflectionClass($classloader);
-    $this->assertTrue($refClass->hasMethod('loadClass'), 'Container has a classloader');
+    $this->assertTrue($classloader instanceof ClassLoaderInterface, 'Container has a classloader');
     // Check that the location of the new module is registered.
     $modules = $container->getParameter('container.modules');
     $this->assertEqual($modules['service_provider_test'], drupal_get_filename('module', 'service_provider_test'));
