diff --git a/core/core.services.yml b/core/core.services.yml
index 9c3f606..de53ad9 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -999,11 +999,24 @@ services:
   current_user:
     class: Drupal\Core\Session\AccountProxy
     arguments: ['@authentication', '@request_stack']
+  session_handler.storage:
+    class: Drupal\Core\Session\SessionHandler
+    arguments: ['@request_stack', '@database']
+    calls:
+      - [setSessionManager, ['@session_manager']]
+    tags:
+      - { name: backend_overridable }
+  session_handler.write_check:
+    class: Symfony\Component\HttpFoundation\Session\Storage\Handler\WriteCheckSessionHandler
+    tags:
+      - { name: session_handler_proxy, priority: 100 }
   session_manager:
     class: Drupal\Core\Session\SessionManager
     arguments: ['@request_stack', '@database', '@session_manager.metadata_bag', '@settings']
     tags:
       - { name: backend_overridable }
+    calls:
+      - [setSaveHandler, ['@session_handler']]
   session_manager.metadata_bag:
     class: Drupal\Core\Session\MetadataBag
     arguments: ['@settings']
diff --git a/core/lib/Drupal/Core/CoreServiceProvider.php b/core/lib/Drupal/Core/CoreServiceProvider.php
index db54f91..4351046 100644
--- a/core/lib/Drupal/Core/CoreServiceProvider.php
+++ b/core/lib/Drupal/Core/CoreServiceProvider.php
@@ -11,6 +11,7 @@
 use Drupal\Core\Cache\ListCacheBinsPass;
 use Drupal\Core\DependencyInjection\Compiler\BackendCompilerPass;
 use Drupal\Core\DependencyInjection\Compiler\StackedKernelPass;
+use Drupal\Core\DependencyInjection\Compiler\StackedSessionHandlerPass;
 use Drupal\Core\DependencyInjection\Compiler\RegisterStreamWrappersPass;
 use Drupal\Core\DependencyInjection\ServiceProviderInterface;
 use Drupal\Core\DependencyInjection\ContainerBuilder;
@@ -54,6 +55,8 @@ public function register(ContainerBuilder $container) {
 
     $container->addCompilerPass(new StackedKernelPass());
 
+    $container->addCompilerPass(new StackedSessionHandlerPass());
+
     // Collect tagged handler services as method calls on consumer services.
     $container->addCompilerPass(new TaggedHandlersPass());
     $container->addCompilerPass(new RegisterStreamWrappersPass());
diff --git a/core/lib/Drupal/Core/DependencyInjection/Compiler/StackedSessionHandlerPass.php b/core/lib/Drupal/Core/DependencyInjection/Compiler/StackedSessionHandlerPass.php
new file mode 100644
index 0000000..32ef407
--- /dev/null
+++ b/core/lib/Drupal/Core/DependencyInjection/Compiler/StackedSessionHandlerPass.php
@@ -0,0 +1,51 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\DependencyInjection\Compiler\StackedSessionHandlerPass.
+ */
+
+namespace Drupal\Core\DependencyInjection\Compiler;
+
+use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Reference;
+
+/**
+ * Provides a compiler pass for stacked session save handlers.
+ */
+class StackedSessionHandlerPass implements CompilerPassInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function process(ContainerBuilder $container) {
+
+    if ($container->hasDefinition('session_handler')) {
+      return;
+    }
+
+    $session_handler_proxies = [];
+    $priorities = [];
+
+    foreach ($container->findTaggedServiceIds('session_handler_proxy') as $id => $attributes) {
+      $priorities[$id] = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0;
+      $session_handler_proxies[$id] = $container->getDefinition($id);
+    }
+
+    array_multisort($priorities, SORT_ASC, $session_handler_proxies);
+
+    $decorated_id = 'session_handler.storage';
+    foreach ($session_handler_proxies as $id => $decorator) {
+      // Prepend the inner session handler as first constructor argument.
+      $arguments = $decorator->getArguments();
+      array_unshift($arguments, new Reference($decorated_id));
+      $decorator->setArguments($arguments);
+
+      $decorated_id = $id;
+    }
+
+    $container->setAlias('session_handler', $decorated_id);
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Session/SessionHandler.php b/core/lib/Drupal/Core/Session/SessionHandler.php
index 4be86ff..1034261 100644
--- a/core/lib/Drupal/Core/Session/SessionHandler.php
+++ b/core/lib/Drupal/Core/Session/SessionHandler.php
@@ -50,15 +50,12 @@ class SessionHandler extends AbstractProxy implements \SessionHandlerInterface {
   /**
    * Constructs a new SessionHandler instance.
    *
-   * @param \Drupal\Core\Session\SessionManagerInterface $session_manager
-   *   The session manager.
    * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
    *   The request stack.
    * @param \Drupal\Core\Database\Connection $connection
    *   The database connection.
    */
-  public function __construct(SessionManagerInterface $session_manager, RequestStack $request_stack, Connection $connection) {
-    $this->sessionManager = $session_manager;
+  public function __construct(RequestStack $request_stack, Connection $connection) {
     $this->requestStack = $request_stack;
     $this->connection = $connection;
   }
@@ -273,6 +270,22 @@ public function gc($lifetime) {
   }
 
   /**
+   * Sets the session manager.
+   *
+   * @param \Drupal\Core\Session\SessionManagerInterface $session_manager
+   *   The session manager.
+   *
+   * @todo Remove dependency on session manager.
+   *   @see https://www.drupal.org/node/2342593
+   *   @see https://www.drupal.org/node/2338727
+   *
+   * @internal
+   */
+  public function setSessionManager(SessionManagerInterface $session_manager) {
+    $this->sessionManager = $session_manager;
+  }
+
+  /**
    * Deletes a session cookie.
    *
    * @param string $name
diff --git a/core/lib/Drupal/Core/Session/SessionManager.php b/core/lib/Drupal/Core/Session/SessionManager.php
index efb3b7a..3c98c2f 100644
--- a/core/lib/Drupal/Core/Session/SessionManager.php
+++ b/core/lib/Drupal/Core/Session/SessionManager.php
@@ -10,10 +10,8 @@
 use Drupal\Component\Utility\Crypt;
 use Drupal\Core\Database\Connection;
 use Drupal\Core\Session\AnonymousUserSession;
-use Drupal\Core\Session\SessionHandler;
 use Drupal\Core\Site\Settings;
 use Symfony\Component\HttpFoundation\RequestStack;
-use Symfony\Component\HttpFoundation\Session\Storage\Handler\WriteCheckSessionHandler;
 use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage;
 
 /**
@@ -78,6 +76,8 @@ class SessionManager extends NativeSessionStorage implements SessionManagerInter
   /**
    * Constructs a new session manager instance.
    *
+   * @param \Symfony\Component\HttpFoundation\Session\Storage\Proxy\AbstractProxy|\Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeSessionHandler|\SessionHandlerInterface|NULL $save_handler
+   *   The session save handler.
    * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
    *   The request stack.
    * @param \Drupal\Core\Database\Connection $connection
@@ -92,13 +92,7 @@ public function __construct(RequestStack $request_stack, Connection $connection,
     $this->requestStack = $request_stack;
     $this->connection = $connection;
 
-    // Register the default session handler.
-    // @todo Extract session storage from session handler into a service.
-    $save_handler = new SessionHandler($this, $this->requestStack, $this->connection);
-    $write_check_handler = new WriteCheckSessionHandler($save_handler);
-    $this->setSaveHandler($write_check_handler);
-
-    parent::__construct($options, $write_check_handler, $metadata_bag);
+    parent::__construct($options, NULL, $metadata_bag);
 
     $this->setMixedMode($settings->get('mixed_mode_sessions', FALSE));
 
