diff --git a/core/lib/Drupal/Component/Discovery/YamlDiscovery.php b/core/lib/Drupal/Component/Discovery/YamlDiscovery.php
index 1d147fd08ba1ff29acc98a36e35507f24e874b04..002327de8b5d972502ecac6121b1cb13f2beac80 100644
--- a/core/lib/Drupal/Component/Discovery/YamlDiscovery.php
+++ b/core/lib/Drupal/Component/Discovery/YamlDiscovery.php
@@ -8,6 +8,7 @@
 namespace Drupal\Component\Discovery;
 
 use Drupal\Component\Serialization\Yaml;
+use Drupal\Component\FileCache\FileCacheFactory;
 
 /**
  * Provides discovery for YAML files within a given set of directories.
@@ -47,10 +48,27 @@ public function __construct($name, array $directories) {
    */
   public function findAll() {
     $all = array();
-    foreach ($this->findFiles() as $provider => $file) {
-      // If a file is empty or its contents are commented out, return an empty
-      // array instead of NULL for type consistency.
-      $all[$provider] = Yaml::decode(file_get_contents($file)) ?: [];
+
+    $files = $this->findFiles();
+    $provider_by_files = array_flip($files);
+
+    $file_cache = FileCacheFactory::get('yaml_discovery:' . $this->name);
+
+    // Try to load from the file cache first.
+    foreach ($file_cache->getMultiple($files) as $file => $data) {
+      $all[$provider_by_files[$file]] = $data;
+      unset($provider_by_files[$file]);
+    }
+
+    // If there are files left that were not returned from the cache, load and
+    // parse them now. This list was flipped above and is keyed by filename.
+    if ($provider_by_files) {
+      foreach ($provider_by_files as $file => $provider) {
+        // If a file is empty or its contents are commented out, return an empty
+        // array instead of NULL for type consistency.
+        $all[$provider] = Yaml::decode(file_get_contents($file)) ?: [];
+        $file_cache->set($file, $all[$provider]);
+      }
     }
 
     return $all;
diff --git a/core/lib/Drupal/Component/FileCache/ApcuFileCacheBackend.php b/core/lib/Drupal/Component/FileCache/ApcuFileCacheBackend.php
new file mode 100644
index 0000000000000000000000000000000000000000..25b6097504ddffde554fc17e73634b03d89327e0
--- /dev/null
+++ b/core/lib/Drupal/Component/FileCache/ApcuFileCacheBackend.php
@@ -0,0 +1,36 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Component\FileCache\ApcuFileCacheBackend.
+ */
+
+namespace Drupal\Component\FileCache;
+
+/**
+ * APCu backend for the file cache.
+ */
+class ApcuFileCacheBackend implements FileCacheBackendInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function fetch(array $cids) {
+    return apc_fetch($cids);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function store($cid, $data) {
+    apc_store($cid, $data);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function delete($cid) {
+    apc_delete($cid);
+  }
+
+}
diff --git a/core/lib/Drupal/Component/FileCache/FileCache.php b/core/lib/Drupal/Component/FileCache/FileCache.php
new file mode 100644
index 0000000000000000000000000000000000000000..761d490f99699e820649917c2a10ca8bd2c0a17e
--- /dev/null
+++ b/core/lib/Drupal/Component/FileCache/FileCache.php
@@ -0,0 +1,156 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Component\FileCache\FileCache.
+ */
+
+namespace Drupal\Component\FileCache;
+
+/**
+ * Allows to cache data based on file modification dates.
+ */
+class FileCache implements FileCacheInterface {
+
+  /**
+   * Prefix that is used for cache entries.
+   *
+   * @var string
+   */
+  protected $prefix;
+
+  /**
+   * Static cache that contains already loaded cache entries.
+   *
+   * @var array
+   */
+  protected static $cached = [];
+
+  /**
+   * The collection identifier of this cache.
+   *
+   * @var string
+   */
+  protected $collection;
+
+  /**
+   * The cache backend backing this FileCache object.
+   *
+   * @var \Drupal\Component\FileCache\FileCacheBackendInterface
+   */
+  protected $cache;
+
+  /**
+   * Constructs a FileCache object.
+   *
+   * @param string $prefix
+   *   The cache prefix.
+   * @param string $collection
+   *   A collection identifier to ensure that the same files could be cached for
+   *   different purposes without clashing.
+   * @param string|null $cache_backend_class
+   *   (optional) The class that should be used as cache backend.
+   * @param array $cache_backend_configuration
+   *   (optional) The configuration for the backend class.
+   */
+  public function __construct($prefix, $collection, $cache_backend_class = NULL, array $cache_backend_configuration = []) {
+
+    if (empty($prefix)) {
+      throw new \InvalidArgumentException('Required prefix configuration is missing');
+    }
+
+    $this->prefix = $prefix;
+    $this->collection = $collection;
+
+    if (isset($cache_backend_class)) {
+      $this->cache = new $cache_backend_class($cache_backend_configuration);
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function get($filepath) {
+    $filepaths = [$filepath];
+    $cached = $this->getMultiple($filepaths);
+    return isset($cached[$filepath]) ? $cached[$filepath] : NULL;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getMultiple(array $filepaths) {
+    $file_data = [];
+    $remaining_cids = [];
+
+    // First load from the static cache what we can.
+    foreach ($filepaths as $filepath) {
+      if (!file_exists($filepath)) {
+        continue;
+      }
+
+      $realpath = realpath($filepath);
+      // If the file exists but realpath returns nothing, it is using a stream
+      // wrapper, those are not supported.
+      if (empty($realpath)) {
+        continue;
+      }
+
+      $cid = $this->prefix . ':' . $this->collection . ':' . $realpath;
+      if (isset(static::$cached[$cid]) && static::$cached[$cid]['mtime'] == filemtime($filepath)) {
+        $file_data[$filepath] = static::$cached[$cid]['data'];
+      }
+      else {
+        // Collect a list of cache IDs that we still need to fetch from cache
+        // backend.
+        $remaining_cids[$cid] = $filepath;
+      }
+    }
+
+    // If there are any cache IDs left to fetch from the cache backend.
+    if ($remaining_cids && $this->cache) {
+      $cache_results = $this->cache->fetch(array_keys($remaining_cids)) ?: [];
+      foreach ($cache_results as $cid => $cached) {
+        $filepath = $remaining_cids[$cid];
+        if ($cached['mtime'] == filemtime($filepath)) {
+          $file_data[$cached['filepath']] = $cached['data'];
+          static::$cached[$cid] = $cached;
+        }
+      }
+    }
+
+    return $file_data;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function set($filepath, $data) {
+    $realpath = realpath($filepath);
+    $cached = [
+      'mtime' => filemtime($filepath),
+      'filepath' => $filepath,
+      'data' => $data,
+    ];
+
+    $cid = $this->prefix . ':' . $this->collection . ':' . $realpath;
+    static::$cached[$cid] = $cached;
+    if ($this->cache) {
+      $this->cache->store($cid, $cached);
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function delete($filepath) {
+    $realpath = realpath($filepath);
+    $cid = $this->prefix . ':' . $this->collection . ':' . $realpath;
+
+    unset(static::$cached[$cid]);
+    if ($this->cache) {
+      $this->cache->delete($cid);
+    }
+  }
+
+}
diff --git a/core/lib/Drupal/Component/FileCache/FileCacheBackendInterface.php b/core/lib/Drupal/Component/FileCache/FileCacheBackendInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..ce31615564ced2103d8264b31dd9ce90d29667fc
--- /dev/null
+++ b/core/lib/Drupal/Component/FileCache/FileCacheBackendInterface.php
@@ -0,0 +1,44 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Component\FileCache\FileCacheBackendInterface.
+ */
+
+namespace Drupal\Component\FileCache;
+
+/**
+ * Defines an interface inspired by APCu for FileCache backends.
+ */
+interface FileCacheBackendInterface {
+
+  /**
+   * Fetches data from the cache backend.
+   *
+   * @param array $cids
+   *   The cache IDs to fetch.
+   *
+   * @return array
+   *   An array containing cache entries keyed by cache ID.
+   */
+  public function fetch(array $cids);
+
+  /**
+   * Stores data into a cache backend.
+   *
+   * @param string $cid
+   *   The cache ID to store data to.
+   * @param mixed $data
+   *   The data to store.
+   */
+  public function store($cid, $data);
+
+  /**
+   * Deletes data from a cache backend.
+   *
+   * @param string $cid
+   *   The cache ID to delete.
+   */
+  public function delete($cid);
+
+}
diff --git a/core/lib/Drupal/Component/FileCache/FileCacheFactory.php b/core/lib/Drupal/Component/FileCache/FileCacheFactory.php
new file mode 100644
index 0000000000000000000000000000000000000000..df391c0183ff9937e6f43520903350204b611a1b
--- /dev/null
+++ b/core/lib/Drupal/Component/FileCache/FileCacheFactory.php
@@ -0,0 +1,107 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\Component\FileCache\FileCacheFactory.
+ */
+
+namespace Drupal\Component\FileCache;
+
+/**
+ * Creates a FileCache object.
+ */
+class FileCacheFactory {
+
+  /**
+   * The configuration used to create FileCache objects.
+   *
+   * @var array $configuration
+   */
+  protected static $configuration;
+
+  /**
+   * The cache prefix.
+   *
+   * @var string
+   */
+  protected static $prefix;
+
+  /**
+   * Instantiates a FileCache object for a given collection identifier.
+   *
+   * @param string $collection
+   *   The collection identifier for this FileCache.
+   * @param array $default_configuration
+   *   (optional) The default configuration for this FileCache collection. This
+   *   can be used to e.g. specify default usage of a FileCache class.
+   *
+   * @return \Drupal\Component\FileCache\FileCacheInterface
+   *   The initialized FileCache object.
+   */
+  public static function get($collection, $default_configuration = []) {
+    $default_configuration += [
+      'class' => '\Drupal\Component\FileCache\FileCache',
+      'collection' => $collection,
+      'cache_backend_class' => NULL,
+      'cache_backend_configuration' => [],
+    ];
+
+    $configuration = [];
+    if (isset(static::$configuration[$collection])) {
+      $configuration = static::$configuration[$collection];
+    }
+    elseif (isset(static::$configuration['default'])) {
+      $configuration = static::$configuration['default'];
+    }
+
+    // Add defaults to the configuration.
+    $configuration = $configuration + $default_configuration;
+
+    $class = $configuration['class'];
+    return new $class(static::getPrefix(), $configuration['collection'], $configuration['cache_backend_class'], $configuration['cache_backend_configuration']);
+  }
+
+  /**
+   * Gets the configuration used for constructing future file cache objects.
+   *
+   * @return array
+   *   The configuration that is used.
+   */
+  public static function getConfiguration() {
+    return static::$configuration;
+  }
+
+  /**
+   * Sets the configuration to use for constructing future file cache objects.
+   *
+   * @param array $configuration
+   *   The configuration to use.
+   */
+  public static function setConfiguration($configuration) {
+    static::$configuration = $configuration;
+  }
+
+  /**
+   * Returns the cache prefix.
+   *
+   * @return string
+   *   The cache prefix.
+   */
+  public static function getPrefix() {
+    return static::$prefix;
+  }
+
+  /**
+   * Sets the cache prefix that should be used.
+   *
+   * Should be set to a secure, unique key to prevent cache pollution by a
+   * third party.
+   *
+   * @param string $prefix
+   *   The cache prefix.
+   */
+  public static function setPrefix($prefix) {
+    static::$prefix = $prefix;
+  }
+
+}
diff --git a/core/lib/Drupal/Component/FileCache/FileCacheInterface.php b/core/lib/Drupal/Component/FileCache/FileCacheInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..e347783538f76ba372f7df0a2e8bec0eb9b04ffb
--- /dev/null
+++ b/core/lib/Drupal/Component/FileCache/FileCacheInterface.php
@@ -0,0 +1,64 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Component\FileCache\FileCacheInterface.
+ */
+
+namespace Drupal\Component\FileCache;
+
+/**
+ * Interface for objects that allow caching file data.
+ *
+ * Parsing YAML, annotations or similar data out of files can be a
+ * time-consuming process, especially since those files usually don't change
+ * and identical data is parsed over and over again.
+ *
+ * File cache is a self-contained caching layer for such processing, that relies
+ * on the file modification to ensure that cached data is still up to date and
+ * does not need to be invalidated externally.
+ */
+interface FileCacheInterface {
+
+  /**
+   * Gets data based on a filename.
+   *
+   * @param string $filepath
+   *   Path of the file that the cached data is based on.
+   *
+   * @return mixed|null
+   *   The data that was persisted with set() or NULL if there is no data
+   *   or the file has been modified.
+   */
+  public function get($filepath);
+
+  /**
+   * Gets data based on filenames.
+   *
+   * @param string[] $filepaths
+   *   List of file paths used as cache identifiers.
+   *
+   * @return array
+   *   List of cached data keyed by the passed in file paths.
+   */
+  public function getMultiple(array $filepaths);
+
+  /**
+   * Stores data based on a filename.
+   *
+   * @param string $filepath
+   *   Path of the file that the cached data is based on.
+   * @param mixed $data
+   *   The data that should be cached.
+   */
+  public function set($filepath, $data);
+
+  /**
+   * Deletes data from the cache.
+   *
+   * @param string $filepath
+   *   Path of the file that the cached data is based on.
+   */
+  public function delete($filepath);
+
+}
diff --git a/core/lib/Drupal/Component/FileCache/NullFileCache.php b/core/lib/Drupal/Component/FileCache/NullFileCache.php
new file mode 100644
index 0000000000000000000000000000000000000000..84c64ccbef69c6538fb04d14f16e5a1a1a39efe9
--- /dev/null
+++ b/core/lib/Drupal/Component/FileCache/NullFileCache.php
@@ -0,0 +1,58 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Component\FileCache\NullFileCache.
+ */
+
+namespace Drupal\Component\FileCache;
+
+/**
+ * Null implementation for the file cache.
+ */
+class NullFileCache implements FileCacheInterface {
+
+  /**
+   * Constructs a FileCache object.
+   *
+   * @param string $prefix
+   *   A prefix that is used as a prefix, should be set to a secure, unique key
+   *   to prevent cache pollution by a third party.
+   * @param string $collection
+   *   A collection identifier to ensure that the same files could be cached for
+   *   different purposes without clashing.
+   * @param string|null $cache_backend_class
+   *   (optional) The class that should be used as cache backend.
+   * @param array $cache_backend_configuration
+   *   (optional) The configuration for the backend class.
+   */
+  public function __construct($prefix, $collection, $cache_backend_class = NULL, array $cache_backend_configuration = []) {
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function get($filepath) {
+    return NULL;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getMultiple(array $filepaths) {
+    return [];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function set($filepath, $data) {
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function delete($filepath) {
+  }
+
+}
diff --git a/core/lib/Drupal/Core/DependencyInjection/YamlFileLoader.php b/core/lib/Drupal/Core/DependencyInjection/YamlFileLoader.php
index d4ae53e2d0bf215d6182a2a40216a4cf9b59e8b6..77484de60f2dfe913f046358858e1fa2aeb81d8a 100644
--- a/core/lib/Drupal/Core/DependencyInjection/YamlFileLoader.php
+++ b/core/lib/Drupal/Core/DependencyInjection/YamlFileLoader.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\Core\DependencyInjection;
 
+use Drupal\Component\FileCache\FileCacheFactory;
 use Drupal\Component\Serialization\Yaml;
 use Symfony\Component\DependencyInjection\Alias;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -34,30 +35,22 @@ class YamlFileLoader
 {
 
     /**
-     * Statically cached yaml files.
-     *
-     * Especially during tests, YAML files are re-parsed often.
-     *
-     * @var array
+     * @var \Drupal\Core\DependencyInjection\ContainerBuilder $container
      */
-    static protected $yaml = array();
+    protected $container;
 
     /**
-     * @param \Drupal\Core\DependencyInjection\ContainerBuilder $container
+     * File cache object.
+     *
+     * @var \Drupal\Component\FileCache\FileCacheInterface
      */
-    protected $container;
+    protected $fileCache;
 
-    public function __construct(ContainerBuilder $container)
-    {
-      $this->container = $container;
-    }
 
-    /**
-     * Resets the internal cache. This method is mostly useful for tests.
-     */
-    public static function reset()
+    public function __construct(ContainerBuilder $container)
     {
-        static::$yaml = array();
+        $this->container = $container;
+        $this->fileCache = FileCacheFactory::get('container_yaml_loader');
     }
 
     /**
@@ -67,10 +60,14 @@ public static function reset()
      */
     public function load($file)
     {
-        if (!isset(static::$yaml[$file])) {
-          static::$yaml[$file] = $this->loadFile($file);
+        // Load from the file cache, fall back to loading the file.
+        // @todo Refactor this to cache parsed definition objects in
+        //   https://www.drupal.org/node/2464053
+        $content = $this->fileCache->get($file);
+        if (!$content) {
+            $content = $this->loadFile($file);
+            $this->fileCache->set($file, $content);
         }
-        $content = static::$yaml[$file];
 
         // Not supported.
         //$this->container->addResource(new FileResource($path));
diff --git a/core/lib/Drupal/Core/DrupalKernel.php b/core/lib/Drupal/Core/DrupalKernel.php
index 859240280e833b015df4bf736602dce921d64c96..e57f9defb97234a9b80bdab6b50f65b44178cba5 100644
--- a/core/lib/Drupal/Core/DrupalKernel.php
+++ b/core/lib/Drupal/Core/DrupalKernel.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\Core;
 
+use Drupal\Component\FileCache\FileCacheFactory;
 use Drupal\Component\ProxyBuilder\ProxyDumper;
 use Drupal\Component\Utility\Crypt;
 use Drupal\Component\Utility\Timer;
@@ -410,6 +411,28 @@ public function boot() {
     if (!$this->sitePath) {
       throw new \Exception('Kernel does not have site path set before calling boot()');
     }
+
+    // Initialize the FileCacheFactory component. We have to do it here instead
+    // of in \Drupal\Component\FileCache\FileCacheFactory because we can not use
+    // the Settings object in a component.
+    $configuration = Settings::get('file_cache');
+
+    // Provide a default configuration, if not set.
+    if (!isset($configuration['default'])) {
+      $configuration['default'] = [
+        'class' => '\Drupal\Component\FileCache\FileCache',
+        'cache_backend_class' => NULL,
+        'cache_backend_configuration' => [],
+      ];
+      // @todo Use extension_loaded('apcu') for non-testbot
+      //  https://www.drupal.org/node/2447753.
+      if (function_exists('apc_fetch')) {
+        $configuration['default']['cache_backend_class'] = '\Drupal\Component\FileCache\ApcuFileCacheBackend';
+      }
+    }
+    FileCacheFactory::setConfiguration($configuration);
+    FileCacheFactory::setPrefix(hash('sha256', Settings::get('hash_salt')));
+
     // Initialize the container.
     $this->initializeContainer();
 
diff --git a/core/lib/Drupal/Core/Extension/ExtensionDiscovery.php b/core/lib/Drupal/Core/Extension/ExtensionDiscovery.php
index 4681977ddde9568e69ba1c9f28503a4d373d251b..fbd8f1b3e2b14d74d77cae9fcfc32de7c3e9179b 100644
--- a/core/lib/Drupal/Core/Extension/ExtensionDiscovery.php
+++ b/core/lib/Drupal/Core/Extension/ExtensionDiscovery.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\Core\Extension;
 
+use Drupal\Component\FileCache\FileCacheFactory;
 use Drupal\Core\Extension\Discovery\RecursiveExtensionFilterIterator;
 use Drupal\Core\Site\Settings;
 
@@ -80,6 +81,13 @@ class ExtensionDiscovery {
    */
   protected $root;
 
+  /**
+   * The file cache object.
+   *
+   * @var \Drupal\Component\FileCache\FileCacheInterface
+   */
+  protected $fileCache;
+
   /**
    * Constructs a new ExtensionDiscovery object.
    *
@@ -88,6 +96,7 @@ class ExtensionDiscovery {
    */
   public function __construct($root) {
     $this->root = $root;
+    $this->fileCache = FileCacheFactory::get('extension_discovery');
   }
 
   /**
@@ -406,6 +415,12 @@ protected function scanDirectory($dir, $include_tests) {
       if (!preg_match(static::PHP_FUNCTION_PATTERN, $fileinfo->getBasename('.info.yml'))) {
         continue;
       }
+
+      if ($cached_extension = $this->fileCache->get($fileinfo->getPathName())) {
+        $files[$cached_extension->getType()][$key] = $cached_extension;
+        continue;
+      }
+
       // Determine extension type from info file.
       $type = FALSE;
       $file = $fileinfo->openFile('r');
@@ -441,6 +456,7 @@ protected function scanDirectory($dir, $include_tests) {
       $extension->origin = $dir;
 
       $files[$type][$key] = $extension;
+      $this->fileCache->set($fileinfo->getPathName(), $extension);
     }
     return $files;
   }
diff --git a/core/modules/simpletest/src/WebTestBase.php b/core/modules/simpletest/src/WebTestBase.php
index 7b98640845f502538a1052e289a0edd9d8fc9927..9dd2f1ad4f9ca8b48b2e33125534909090c7e90c 100644
--- a/core/modules/simpletest/src/WebTestBase.php
+++ b/core/modules/simpletest/src/WebTestBase.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\simpletest;
 
+use Drupal\Component\FileCache\FileCacheFactory;
 use Drupal\Component\Serialization\Json;
 use Drupal\Component\Serialization\Yaml;
 use Drupal\Component\Utility\Crypt;
@@ -1071,8 +1072,9 @@ protected function setContainerParameter($name, $value) {
     $services['parameters'][$name] = $value;
     file_put_contents($filename, Yaml::encode($services));
 
-    // Clear the YML file cache.
-    YamlFileLoader::reset();
+    // Ensure that the cache is deleted for the yaml file loader.
+    $file_cache = FileCacheFactory::get('container_yaml_loader');
+    $file_cache->delete($filename);
   }
 
   /**
diff --git a/core/tests/Drupal/Tests/Component/FileCache/FileCacheFactoryTest.php b/core/tests/Drupal/Tests/Component/FileCache/FileCacheFactoryTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..206de2c699e153f8f1953fecbad5e9ed4a1426f4
--- /dev/null
+++ b/core/tests/Drupal/Tests/Component/FileCache/FileCacheFactoryTest.php
@@ -0,0 +1,95 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\Component\FileCache\FileCacheFactoryTest.
+ */
+
+namespace Drupal\Tests\Component\FileCache;
+
+use Drupal\Component\FileCache\FileCacheFactory;
+use Drupal\Tests\UnitTestCase;
+
+/**
+ * @coversDefaultClass \Drupal\Component\FileCache\FileCacheFactory
+ * @group FileCache
+ */
+class FileCacheFactoryTest extends UnitTestCase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    $settings = [
+      'collection' => 'test-23',
+      'cache_backend_class' => '\Drupal\Tests\Component\FileCache\StaticFileCacheBackend',
+      'cache_backend_configuration' => [
+        'bin' => 'dog',
+      ],
+    ];
+    $configuration = FileCacheFactory::getConfiguration();
+    if (!$configuration) {
+      $configuration = [];
+    }
+    $configuration += [ 'test_foo_settings' => $settings ];
+    FileCacheFactory::setConfiguration($configuration);
+    FileCacheFactory::setPrefix('prefix');
+  }
+
+  /**
+   * @covers ::get
+   */
+  public function testGet() {
+    $file_cache = FileCacheFactory::get('test_foo_settings', []);
+
+    // Ensure the right backend and configuration is used.
+    $filename = __DIR__ . '/Fixtures/llama-23.txt';
+    $realpath = realpath($filename);
+    $cid = 'prefix:test-23:' . $realpath;
+
+    $file_cache->set($filename, 23);
+
+    $static_cache = new StaticFileCacheBackend(['bin' => 'dog']);
+    $result = $static_cache->fetch([$cid]);
+    $this->assertNotEmpty($result);
+
+    // Cleanup static caches.
+    $file_cache->delete($filename);
+  }
+
+  /**
+   * @covers ::get
+   *
+   * @expectedException \InvalidArgumentException
+   * @expectedExceptionMessage Required prefix configuration is missing
+   */
+  public function testGetNoPrefix() {
+    FileCacheFactory::setPrefix(NULL);
+    FileCacheFactory::get('test_foo_settings', []);
+  }
+
+  /**
+   * @covers ::getConfiguration
+   * @covers ::setConfiguration
+   */
+  public function testGetSetConfiguration() {
+    $configuration = FileCacheFactory::getConfiguration();
+    $configuration['test_foo_bar'] = ['bar' => 'llama'];
+    FileCacheFactory::setConfiguration($configuration);
+    $configuration = FileCacheFactory::getConfiguration();
+    $this->assertEquals(['bar' => 'llama'], $configuration['test_foo_bar']);
+  }
+
+  /**
+   * @covers ::getPrefix
+   * @covers ::setPrefix
+   */
+  public function testGetSetPrefix() {
+    $prefix = $this->randomMachineName();
+    FileCacheFactory::setPrefix($prefix);
+    $this->assertEquals($prefix, FileCacheFactory::getPrefix());
+  }
+
+}
diff --git a/core/tests/Drupal/Tests/Component/FileCache/FileCacheTest.php b/core/tests/Drupal/Tests/Component/FileCache/FileCacheTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..9e51798526d945566f5825b315e1ca1259626451
--- /dev/null
+++ b/core/tests/Drupal/Tests/Component/FileCache/FileCacheTest.php
@@ -0,0 +1,147 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\Component\FileCache\FileCacheTest.
+ */
+
+namespace Drupal\Tests\Component\FileCache;
+
+use Drupal\Component\FileCache\FileCache;
+use Drupal\Tests\UnitTestCase;
+
+/**
+ * @coversDefaultClass \Drupal\Component\FileCache\FileCache
+ * @group FileCache
+ */
+class FileCacheTest extends UnitTestCase {
+
+  /**
+   * FileCache object used for the tests.
+   *
+   * @var \Drupal\Component\FileCache\FileCacheInterface
+   */
+  protected $fileCache;
+
+  /**
+   * Static FileCache object used for verification of tests.
+   *
+   * @var \Drupal\Component\FileCache\FileCacheBackendInterface
+   */
+  protected $staticFileCache;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    $this->fileCache = new FileCache('prefix', 'test', '\Drupal\Tests\Component\FileCache\StaticFileCacheBackend', ['bin' => 'llama']);
+    $this->staticFileCache = new StaticFileCacheBackend(['bin' => 'llama']);
+  }
+
+  /**
+   * @covers ::get
+   * @covers ::__construct
+   */
+  public function testGet() {
+    // Test a cache miss.
+    $result = $this->fileCache->get(__DIR__ . '/Fixtures/no-llama-42.yml');
+    $this->assertNull($result);
+
+    // Test a cache hit.
+    $filename = __DIR__ . '/Fixtures/llama-42.txt';
+    $realpath = realpath($filename);
+    $cid = 'prefix:test:' . $realpath;
+    $data = [
+      'mtime' => filemtime($realpath),
+      'filepath' => $realpath,
+      'data' => 42,
+    ];
+
+    $this->staticFileCache->store($cid, $data);
+
+    $result = $this->fileCache->get($filename);
+    $this->assertEquals(42, $result);
+
+    // Cleanup static caches.
+    $this->fileCache->delete($filename);
+  }
+
+  /**
+   * @covers ::getMultiple
+   */
+  public function testGetMultiple() {
+    // Test a cache miss.
+    $result = $this->fileCache->getMultiple([__DIR__ . '/Fixtures/no-llama-42.yml']);
+    $this->assertEmpty($result);
+
+    // Test a cache hit.
+    $filename = __DIR__ . '/Fixtures/llama-42.txt';
+    $realpath = realpath($filename);
+    $cid = 'prefix:test:' . $realpath;
+    $data = [
+      'mtime' => filemtime($realpath),
+      'filepath' => $realpath,
+      'data' => 42,
+    ];
+
+    $this->staticFileCache->store($cid, $data);
+
+    $result = $this->fileCache->getMultiple([$filename]);
+    $this->assertEquals([$filename => 42], $result);
+
+    // Test a static cache hit.
+    $file2 = __DIR__ . '/Fixtures/llama-23.txt';
+    $this->fileCache->set($file2, 23);
+
+    $result = $this->fileCache->getMultiple([$filename, $file2]);
+    $this->assertEquals([$filename => 42, $file2 => 23], $result);
+
+    // Cleanup static caches.
+    $this->fileCache->delete($filename);
+    $this->fileCache->delete($file2);
+  }
+
+  /**
+   * @covers ::set
+   */
+  public function testSet() {
+    $filename = __DIR__ . '/Fixtures/llama-23.txt';
+    $realpath = realpath($filename);
+    $cid = 'prefix:test:' . $realpath;
+    $data = [
+      'mtime' => filemtime($realpath),
+      'filepath' => $realpath,
+      'data' => 23,
+    ];
+
+    $this->fileCache->set($filename, 23);
+    $result = $this->staticFileCache->fetch([$cid]);
+    $this->assertEquals([$cid => $data], $result);
+
+    // Cleanup static caches.
+    $this->fileCache->delete($filename);
+  }
+
+  /**
+   * @covers ::delete
+   */
+  public function testDelete() {
+    $filename = __DIR__ . '/Fixtures/llama-23.txt';
+    $realpath = realpath($filename);
+    $cid = 'prefix:test:' . $realpath;
+
+    $this->fileCache->set($filename, 23);
+
+    // Ensure data is removed after deletion.
+    $this->fileCache->delete($filename);
+
+    $result = $this->staticFileCache->fetch([$cid]);
+    $this->assertEquals([], $result);
+
+    $result = $this->fileCache->get($filename);
+    $this->assertNull($result);
+  }
+
+}
diff --git a/core/tests/Drupal/Tests/Component/FileCache/Fixtures/llama-23.txt b/core/tests/Drupal/Tests/Component/FileCache/Fixtures/llama-23.txt
new file mode 100644
index 0000000000000000000000000000000000000000..409940768f2a684935a7d15a29f96e82c487f439
--- /dev/null
+++ b/core/tests/Drupal/Tests/Component/FileCache/Fixtures/llama-23.txt
@@ -0,0 +1 @@
+23
diff --git a/core/tests/Drupal/Tests/Component/FileCache/Fixtures/llama-42.txt b/core/tests/Drupal/Tests/Component/FileCache/Fixtures/llama-42.txt
new file mode 100644
index 0000000000000000000000000000000000000000..d81cc0710eb6cf9efd5b920a8453e1e07157b6cd
--- /dev/null
+++ b/core/tests/Drupal/Tests/Component/FileCache/Fixtures/llama-42.txt
@@ -0,0 +1 @@
+42
diff --git a/core/tests/Drupal/Tests/Component/FileCache/StaticFileCacheBackend.php b/core/tests/Drupal/Tests/Component/FileCache/StaticFileCacheBackend.php
new file mode 100644
index 0000000000000000000000000000000000000000..ed82b8118132e5f2692360e97556b4fa5cd2b425
--- /dev/null
+++ b/core/tests/Drupal/Tests/Component/FileCache/StaticFileCacheBackend.php
@@ -0,0 +1,76 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\Component\FileCache\StaticFileCacheBackend.
+ */
+
+namespace Drupal\Tests\Component\FileCache;
+
+use Drupal\Component\FileCache\FileCacheBackendInterface;
+
+/**
+ * Allows to cache data based on file modification dates in a static cache.
+ */
+class StaticFileCacheBackend implements FileCacheBackendInterface {
+
+  /**
+   * Internal static cache.
+   *
+   * @var array
+   */
+  protected static $cache = [];
+
+  /**
+   * Bin used for storing the data in the static cache.
+   *
+   * @var string
+   */
+  protected $bin;
+
+  /**
+   * Constructs a PHP Storage FileCache backend.
+   *
+   * @param array $configuration
+   *   (optional) Configuration used to configure this object.
+   */
+  public function __construct($configuration) {
+    $this->bin = isset($configuration['bin']) ? $configuration['bin'] : 'file_cache';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function fetch(array $cids) {
+    $result = [];
+    foreach ($cids as $cid) {
+      if (isset(static::$cache[$this->bin][$cid])) {
+        $result[$cid] = static::$cache[$this->bin][$cid];
+      }
+    }
+
+    return $result;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function store($cid, $data) {
+    static::$cache[$this->bin][$cid] = $data;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function delete($cid) {
+    unset(static::$cache[$this->bin][$cid]);
+  }
+
+  /**
+   * Allows tests to reset the static cache to avoid side effects.
+   */
+  public static function reset() {
+    static::$cache = [];
+  }
+
+}
diff --git a/core/tests/Drupal/Tests/UnitTestCase.php b/core/tests/Drupal/Tests/UnitTestCase.php
index c15bff26a3c4ff337912067bad950346d5057f14..9e70a73b9a664ff7e351526068ba6013e3da2581 100644
--- a/core/tests/Drupal/Tests/UnitTestCase.php
+++ b/core/tests/Drupal/Tests/UnitTestCase.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\Tests;
 
+use Drupal\Component\FileCache\FileCacheFactory;
 use Drupal\Component\Utility\Random;
 use Drupal\Core\Cache\CacheTagsInvalidatorInterface;
 use Drupal\Core\DependencyInjection\ContainerBuilder;
@@ -41,6 +42,10 @@ protected function setUp() {
     // a previous test does not leak into this test.
     \Drupal::unsetContainer();
 
+    // Ensure that the NullFileCache implementation is used for the FileCache as
+    // unit tests should not be relying on caches implicitly.
+    FileCacheFactory::setConfiguration(['default' => ['class' => '\Drupal\Component\FileCache\NullFileCache']]);
+
     $this->root = dirname(dirname(substr(__DIR__, 0, -strlen(__NAMESPACE__))));
   }