diff --git a/core/core.services.yml b/core/core.services.yml
index f5ed5db..87abd1a 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -380,7 +380,7 @@ services:
      class: Drupal\Core\Routing\CurrentRouteMatch
      arguments: ['@request_stack']
   event_dispatcher:
-    class: Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher
+    class: Drupal\Core\EventSubscriber\ContainerAwareEventDispatcher
     arguments: ['@service_container']
   controller_resolver:
     class: Drupal\Core\Controller\ControllerResolver
diff --git a/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterKernelListenersPass.php b/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterKernelListenersPass.php
index 59a3591..1c607cb 100644
--- a/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterKernelListenersPass.php
+++ b/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterKernelListenersPass.php
@@ -18,6 +18,8 @@ public function process(ContainerBuilder $container) {
 
     $definition = $container->getDefinition('event_dispatcher');
 
+    $event_subscriber_info = [];
+    $weights = [];
     foreach ($container->findTaggedServiceIds('event_subscriber') as $id => $attributes) {
 
       // We must assume that the class value has been correctly filled, even if the service is created by a factory
@@ -28,7 +30,28 @@ public function process(ContainerBuilder $container) {
       if (!$refClass->implementsInterface($interface)) {
         throw new \InvalidArgumentException(sprintf('Service "%s" must implement interface "%s".', $id, $interface));
       }
-      $definition->addMethodCall('addSubscriberService', array($id, $class));
+
+      // Get all subscribed events.
+      foreach ($class::getSubscribedEvents() as $event_name => $params) {
+        if (is_string($params)) {
+          $event_subscriber_info[$event_name][] = array($id, $params);
+          $weights[$event_name][] = 0;
+        }
+        elseif (is_string($params[0])) {
+          $event_subscriber_info[$event_name][] = array($id, $params[0]);
+          $weights[$event_name][] = isset($params[1]) ? $params[1] : 0;
+        }
+        else {
+          foreach ($params as $listener) {
+            $event_subscriber_info[$event_name][] = array($id, $listener[0]);
+            $weights[$event_name][] = isset($listener[1]) ? $listener[1] : 0;
+          }
+        }
+      }
     }
+    foreach ($weights as $event_name => $sort_weights) {
+      array_multisort($sort_weights, SORT_NUMERIC, $event_subscriber_info[$event_name]);
+    }
+    $definition->addArgument($event_subscriber_info);
   }
 }
diff --git a/core/lib/Drupal/Core/EventSubscriber/ContainerAwareEventDispatcher.php b/core/lib/Drupal/Core/EventSubscriber/ContainerAwareEventDispatcher.php
new file mode 100644
index 0000000..ca466dd
--- /dev/null
+++ b/core/lib/Drupal/Core/EventSubscriber/ContainerAwareEventDispatcher.php
@@ -0,0 +1,214 @@
+<?php
+
+namespace Drupal\Core\EventSubscriber;
+
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\EventDispatcher\Event;
+use Symfony\Component\EventDispatcher\EventDispatcher;
+
+class ContainerAwareEventDispatcher extends EventDispatcher {
+
+  /**
+   * The container from where services are loaded
+   *
+   * @var ContainerInterface
+   */
+  protected $container;
+
+  /**
+   * The service IDs of the event listeners and subscribers
+   *
+   * @var array
+   */
+  protected $listenerIds = array();
+
+  /**
+   * The services registered as listeners
+   *
+   * @var array
+   */
+  protected $listeners = array();
+
+  /**
+   * Constructor.
+   *
+   * @param ContainerInterface $container
+   *   A ContainerInterface instance
+   * @param array $listener_ids
+   *   The listeners known at construction time.
+   */
+  public function __construct(ContainerInterface $container, array $listener_ids = []) {
+    $this->container = $container;
+    $this->listenerIds = $listener_ids;
+  }
+
+  /**
+   * {@inheritDoc}
+   *
+   * Lazily loads listeners for this event from the dependency injection
+   * container.
+   *
+   * @throws \InvalidArgumentException if the service is not defined
+   */
+  public function dispatch($eventName, Event $event = NULL) {
+    if (null === $event) {
+      $event = new Event();
+    }
+
+    $event->setDispatcher($this);
+    $event->setName($eventName);
+    if (isset($this->listenerIds[$eventName])) {
+      foreach ($this->listenerIds[$eventName] as $args) {
+        list($serviceId, $method) = $args;
+        $listener = $this->container->get($serviceId);
+        $listener::$method($event, $eventName, $this);
+        if ($event->isPropagationStopped()) {
+          break;
+        }
+      }
+    }
+    return $event;
+  }
+
+  /**
+   * Adds a service as event listener
+   *
+   * @param string $eventName Event for which the listener is added
+   * @param array $callback The service ID of the listener service & the method
+   *                            name that has to be called
+   * @param integer $priority The higher this value, the earlier an event
+   *   listener will be triggered in the chain. Defaults to 0.
+   *
+   * @throws \InvalidArgumentException
+   */
+  public function addListenerService($eventName, $callback, $priority = 0) {
+    if (!is_array($callback) || 2 !== count($callback)) {
+      throw new \InvalidArgumentException('Expected an array("service", "method") argument');
+    }
+
+    $this->listenerIds[$eventName][] = array(
+      $callback[0],
+      $callback[1],
+      $priority
+    );
+  }
+
+  public function removeListener($eventName, $listener) {
+    $this->lazyLoad($eventName);
+
+    if (isset($this->listeners[$eventName])) {
+      foreach ($this->listeners[$eventName] as $key => $l) {
+        foreach ($this->listenerIds[$eventName] as $i => $args) {
+          list($serviceId, $method, $priority) = $args;
+          if ($key === $serviceId . '.' . $method) {
+            if ($listener === array($l, $method)) {
+              unset($this->listeners[$eventName][$key]);
+              if (empty($this->listeners[$eventName])) {
+                unset($this->listeners[$eventName]);
+              }
+              unset($this->listenerIds[$eventName][$i]);
+              if (empty($this->listenerIds[$eventName])) {
+                unset($this->listenerIds[$eventName]);
+              }
+            }
+          }
+        }
+      }
+    }
+
+    parent::removeListener($eventName, $listener);
+  }
+
+  /**
+   * @see EventDispatcherInterface::hasListeners
+   */
+  public function hasListeners($eventName = NULL) {
+    if (NULL === $eventName) {
+      return (Boolean) count($this->listenerIds) || (Boolean) count($this->listeners);
+    }
+
+    if (isset($this->listenerIds[$eventName])) {
+      return TRUE;
+    }
+
+    return parent::hasListeners($eventName);
+  }
+
+  /**
+   * @see EventDispatcherInterface::getListeners
+   */
+  public function getListeners($eventName = NULL) {
+    if (NULL === $eventName) {
+      foreach (array_keys($this->listenerIds) as $serviceEventName) {
+        $this->lazyLoad($serviceEventName);
+      }
+    }
+    else {
+      $this->lazyLoad($eventName);
+    }
+
+    return parent::getListeners($eventName);
+  }
+
+  /**
+   * Adds a service as event subscriber
+   *
+   * @param string $serviceId The service ID of the subscriber service
+   * @param string $class The service's class name (which must implement
+   *   EventSubscriberInterface)
+   */
+  public function addSubscriberService($serviceId, $class) {
+    foreach ($class::getSubscribedEvents() as $eventName => $params) {
+      if (is_string($params)) {
+        $this->listenerIds[$eventName][] = array($serviceId, $params, 0);
+      }
+      elseif (is_string($params[0])) {
+        $this->listenerIds[$eventName][] = array(
+          $serviceId,
+          $params[0],
+          isset($params[1]) ? $params[1] : 0
+        );
+      }
+      else {
+        foreach ($params as $listener) {
+          $this->listenerIds[$eventName][] = array(
+            $serviceId,
+            $listener[0],
+            isset($listener[1]) ? $listener[1] : 0
+          );
+        }
+      }
+    }
+  }
+
+  /**
+   * Lazily loads listeners for this event from the dependency injection
+   * container.
+   *
+   * @param string $eventName The name of the event to dispatch. The name of
+   *                          the event is the name of the method that is
+   *                          invoked on listeners.
+   */
+  protected function lazyLoad($eventName) {
+    if (isset($this->listenerIds[$eventName])) {
+      foreach ($this->listenerIds[$eventName] as $args) {
+        list($serviceId, $method, $priority) = $args;
+        $listener = $this->container->get($serviceId);
+
+        $key = $serviceId . '.' . $method;
+        if (!isset($this->listeners[$eventName][$key])) {
+          $this->addListener($eventName, array($listener, $method), $priority);
+        }
+        elseif ($listener !== $this->listeners[$eventName][$key]) {
+          parent::removeListener($eventName, array(
+              $this->listeners[$eventName][$key],
+              $method
+            ));
+          $this->addListener($eventName, array($listener, $method), $priority);
+        }
+
+        $this->listeners[$eventName][$key] = $listener;
+      }
+    }
+  }
+}
