diff --git a/core/core.services.yml b/core/core.services.yml
index 1b9aae5..7261d1c 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -881,7 +881,7 @@ services:
     parent: default_plugin_manager
   stream_wrapper_manager:
     class: Drupal\Core\StreamWrapper\StreamWrapperManager
-    arguments: ['@module_handler']
+    arguments: ['@event_dispatcher', '@config.factory']
     calls:
       - [setContainer, ['@service_container']]
   stream_wrapper.public:
diff --git a/core/lib/Drupal/Core/StreamWrapper/StreamWrapperAlterEvent.php b/core/lib/Drupal/Core/StreamWrapper/StreamWrapperAlterEvent.php
new file mode 100644
index 0000000..bf23183
--- /dev/null
+++ b/core/lib/Drupal/Core/StreamWrapper/StreamWrapperAlterEvent.php
@@ -0,0 +1,95 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\StreamWrapper\StreamWrapperAlterEvent.
+ */
+
+namespace Drupal\Core\StreamWrapper;
+
+use Symfony\Component\EventDispatcher\Event;
+
+/**
+ * Event subscribers to alter stream wrapper information.
+ *
+ * @see \Drupal\Core\StreamWrapper\StreamWrapperEvents::ALTER
+ */
+class StreamWrapperAlterEvent extends Event {
+
+  /**
+   * The array of available stream wrappers.
+   *
+   * @var array
+   */
+  protected $streamWrappers = [];
+
+  /**
+   * Constructs a StreamWrapperAlterEvent.
+   *
+   * @param array
+   *   An associative array where keys are scheme names and values are
+   *   themselves associative arrays with the keys class, type and (optionally)
+   *   service_id, and string values.
+   */
+  public function __construct(array $stream_wrappers) {
+    $this->streamWrappers = $stream_wrappers;
+  }
+
+  /**
+   * Sets the stream wrapper for a given name.
+   *
+   * @param string $name
+   *   The name for the stream wrapper.
+   * @param array $info
+   *   An associative array with the keys class, type and (optionally)
+   *   service_id, and string values.
+   *
+   * @return $this
+   */
+  public function setStreamWrapper($name, array $info) {
+    $this->streamWrappers[$name] = $info;
+    return $this;
+  }
+
+  /**
+   * Returns the stream wrapper info for a given name.
+   *
+   * @param string $name
+   *   The name of the stream wrapper.
+   *
+   * @return array
+   *   An associative array with the keys class, type and (optionally)
+   *   service_id, and string values.
+   */
+  public function getStreamWrapper($name) {
+    if (isset($this->streamWrappers[$name])) {
+      return $this->streamWrappers[$name];
+    }
+  }
+
+  /**
+   * Returns whether there is a stream wrapper for the given name.
+   *
+   * @param string $name
+   *   The name of the stream wrapper.
+   *
+   * @return bool
+   *   TRUE if the stream wrappers exits.
+   */
+  public function hasStreamWrapper($name) {
+    return isset($this->streamWrappers[$name]);
+  }
+
+  /**
+   * Returns the stream wrapper information.
+   *
+   * @return array
+   *   An associative array where keys are scheme names and values are
+   *   themselves associative arrays with the keys class, type and (optionally)
+   *   service_id, and string values.
+   */
+  public function getStreamWrappers() {
+    return $this->streamWrappers;
+  }
+
+}
diff --git a/core/lib/Drupal/Core/StreamWrapper/StreamWrapperEvents.php b/core/lib/Drupal/Core/StreamWrapper/StreamWrapperEvents.php
new file mode 100644
index 0000000..98632a4
--- /dev/null
+++ b/core/lib/Drupal/Core/StreamWrapper/StreamWrapperEvents.php
@@ -0,0 +1,22 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\StreamWrapper\StreamWrapperEvents.
+ */
+
+namespace Drupal\Core\StreamWrapper;
+
+/**
+ * Defines stream wrapper events.
+ */
+final class StreamWrapperEvents {
+
+  /**
+   * Name of the event when altering stream wrappers.
+   *
+   * @see \Drupal\Core\StreamWrapper\StreamWrapperManager::register()
+   */
+  const ALTER = 'stream_wrappers.alter';
+
+}
diff --git a/core/lib/Drupal/Core/StreamWrapper/StreamWrapperManager.php b/core/lib/Drupal/Core/StreamWrapper/StreamWrapperManager.php
index 43532a0..aa985ed 100644
--- a/core/lib/Drupal/Core/StreamWrapper/StreamWrapperManager.php
+++ b/core/lib/Drupal/Core/StreamWrapper/StreamWrapperManager.php
@@ -7,8 +7,9 @@
 
 namespace Drupal\Core\StreamWrapper;
 
-use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Config\ConfigFactoryInterface;
 use Symfony\Component\DependencyInjection\ContainerAware;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 
 /**
  * Provides a StreamWrapper manager.
@@ -50,20 +51,28 @@ class StreamWrapperManager extends ContainerAware {
   protected $wrappers = array();
 
   /**
-   * The module handler.
+   * The event dispatcher service.
    *
-   * @var \Drupal\Core\Extension\ModuleHandlerInterface
+   * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
    */
-  protected $moduleHandler;
+  protected $dispatcher;
+
+  /**
+   * @var \Drupal\Core\Config\ConfigFactoryInterface
+   */
+  protected $configFactory;
 
   /**
    * Constructs a StreamWrapperManager object.
    *
-   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
-   *   The module handler.
+   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $dispatcher
+   *   The event dispatcher
+   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
+   *   The config factory.
    */
-  public function __construct(ModuleHandlerInterface $module_handler) {
-    $this->moduleHandler = $module_handler;
+  public function __construct(EventDispatcherInterface $dispatcher, ConfigFactoryInterface $config_factory) {
+    $this->dispatcher = $dispatcher;
+    $this->configFactory = $config_factory;
   }
 
   /**
@@ -279,7 +288,13 @@ public function addStreamWrapper($service_id, $class, $scheme) {
    * Internal use only.
    */
   public function register() {
-    $this->moduleHandler->alter('stream_wrappers', $this->info);
+    $event = new StreamWrapperAlterEvent($this->info);
+
+    // Only expose the private file stream wrapper if a file path has been set.
+    if (!$this->configFactory->get('system.file')->get('path.private')) {
+      unset($this->info['private']);
+    }
+    $this->info = $this->dispatcher->dispatch(StreamWrapperEvents::ALTER, $event)->getStreamWrappers();
 
     foreach ($this->info as $scheme => $info) {
       $this->registerWrapper($scheme, $info['class'], $info['type']);
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index 4eaf7bb..8f5367d 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -310,16 +310,6 @@ function system_theme_suggestions_field(array $variables) {
 }
 
 /**
- * Implements hook_stream_wrappers_alter().
- */
-function system_stream_wrappers_alter(&$wrappers) {
-  // Only register the private file stream wrapper if a file path has been set.
-  if (!\Drupal::config('system.file')->get('path.private')) {
-    unset($wrappers['private']);
-  }
-}
-
-/**
  * Menu item access callback - only installed themes can be accessed.
  */
 function _system_themes_access($theme) {
