diff --git a/core/lib/Drupal.php b/core/lib/Drupal.php
index 7b52d13..9efc0a1 100644
--- a/core/lib/Drupal.php
+++ b/core/lib/Drupal.php
@@ -5,10 +5,32 @@
  * Contains Drupal.
  */
 
+use Drupal\Core\DependencyInjection\PlaceholderContainer;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Drupal\Core\Url;
 
 /**
+ * Initialize \Drupal::$container with a placeholder object.
+ * See https://www.drupal.org/node/2363341
+ *
+ * This technique is the most reliable way to initialize static properties with
+ * non-trivial expressions. It should NOT be used for anything else. Also, the
+ * code being called MUST NOT have any side effects other than initializing the
+ * static properties.
+ *
+ * In general (e.g. in PSR-1), a PHP file should either declare symbols OR have
+ * side-effects, but not both. This specific case is ok only because the side
+ * effect applies to nothing else but the class declared in the same file, and
+ * it happens immediately after the class is being declared. A version of the
+ * class without this initialization applied is never available to the outside
+ * world.
+ *
+ * Note: PHP does not care whether this is called before or after the class
+ * declaration. It is called before only for better visibility.
+ */
+\Drupal::initStaticProperties(NULL);
+
+/**
  * Static Service Container wrapper.
  *
  * Generally, code in Drupal should accept its dependencies via either
@@ -103,15 +125,33 @@ class Drupal {
    * Sets a new global container.
    *
    * @param \Symfony\Component\DependencyInjection\ContainerInterface $container
-   *   A new container instance to replace the current. NULL may be passed by
-   *   testing frameworks to ensure that the global state of a previous
-   *   environment does not leak into a test.
+   *   A new container instance to replace the current.
    */
-  public static function setContainer(ContainerInterface $container = NULL) {
+  public static function setContainer(ContainerInterface $container) {
     static::$container = $container;
   }
 
   /**
+   * Unsets the global container.
+   *
+   * @param string|null $message
+   */
+  public static function unsetContainer($message = NULL) {
+    if (!isset($message)) {
+      $message = '\Drupal::$container was unset with \Drupal::unsetContainer().';
+    }
+    static::setContainer(new PlaceholderContainer($message));
+  }
+
+  /**
+   * Initializes the static properties. Called from within the class file.
+   */
+  public static function initStaticProperties() {
+    $message = '\Drupal::$container is not initialized yet. \Drupal::setContainer() must be called with a real container.';
+    static::setContainer(new PlaceholderContainer($message));
+  }
+
+  /**
    * Returns the currently active global container.
    *
    * @deprecated This method is only useful for the testing environment. It
@@ -120,6 +160,13 @@ public static function setContainer(ContainerInterface $container = NULL) {
    * @return \Symfony\Component\DependencyInjection\ContainerInterface|null
    */
   public static function getContainer() {
+    if (static::$container instanceof PlaceholderContainer) {
+      // Currently, some components depend on this method returning NULL if not
+      // initialized.
+      // @todo Throw an exception instead, and change all code that expects
+      //   NULL.
+      return NULL;
+    }
     return static::$container;
   }
 
@@ -149,7 +196,7 @@ public static function service($id) {
    *   TRUE if the specified service exists, FALSE otherwise.
    */
   public static function hasService($id) {
-    return static::$container && static::$container->has($id);
+    return static::$container->has($id);
   }
 
   /**
@@ -168,7 +215,7 @@ public static function root() {
    *   TRUE if there is a currently active request object, FALSE otherwise.
    */
   public static function hasRequest() {
-    return static::$container && static::$container->has('request_stack') && static::$container->get('request_stack')->getCurrentRequest() !== NULL;
+    return static::$container->has('request_stack') && static::$container->get('request_stack')->getCurrentRequest() !== NULL;
   }
 
   /**
diff --git a/core/lib/Drupal/Core/DependencyInjection/ContainerNotInitializedException.php b/core/lib/Drupal/Core/DependencyInjection/ContainerNotInitializedException.php
new file mode 100644
index 0000000..6de8116
--- /dev/null
+++ b/core/lib/Drupal/Core/DependencyInjection/ContainerNotInitializedException.php
@@ -0,0 +1,15 @@
+<?php
+
+
+namespace Drupal\Core\DependencyInjection;
+
+/**
+ * Exception thrown when a method is called that requires a container, but the
+ * container is not initialized yet.
+ *
+ * @see \Drupal
+ * @see \Drupal\Core\DependencyInjection\PlaceholderContainer
+ */
+class ContainerNotInitializedException extends \Exception {
+
+}
diff --git a/core/lib/Drupal/Core/DependencyInjection/PlaceholderContainer.php b/core/lib/Drupal/Core/DependencyInjection/PlaceholderContainer.php
new file mode 100644
index 0000000..d8a5beb
--- /dev/null
+++ b/core/lib/Drupal/Core/DependencyInjection/PlaceholderContainer.php
@@ -0,0 +1,113 @@
+<?php
+
+
+namespace Drupal\Core\DependencyInjection;
+
+
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\DependencyInjection\ScopeInterface;
+
+/**
+ * A placeholder container that throws an exception whenever it does anything.
+ *
+ * Used in
+ * @see \Drupal
+ */
+class PlaceholderContainer implements ContainerInterface {
+
+  /**
+   * Message for ContainerNotInitializedException.
+   *
+   * @var string
+   */
+  protected $message;
+
+  /**
+   * Constructs a PlaceholderContainer object.
+   *
+   * @param string $exception_message
+   *   Message for ContainerNotInitializedException.
+   */
+  public function __construct($exception_message = NULL) {
+    $this->message = isset($exception_message)
+      ? $exception_message
+      : 'Container not initialized.';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function set($id, $service, $scope = self::SCOPE_CONTAINER) {
+    throw new ContainerNotInitializedException($this->message);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function get($id, $invalidBehavior = self::EXCEPTION_ON_INVALID_REFERENCE) {
+    throw new ContainerNotInitializedException($this->message);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function has($id) {
+    return FALSE;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getParameter($name) {
+    throw new ContainerNotInitializedException($this->message);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function hasParameter($name) {
+    throw new ContainerNotInitializedException($this->message);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setParameter($name, $value) {
+    throw new ContainerNotInitializedException($this->message);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function enterScope($name) {
+    throw new ContainerNotInitializedException($this->message);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function leaveScope($name) {
+    throw new ContainerNotInitializedException($this->message);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function addScope(ScopeInterface $scope) {
+    throw new ContainerNotInitializedException($this->message);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function hasScope($name) {
+    throw new ContainerNotInitializedException($this->message);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isScopeActive($name) {
+    throw new ContainerNotInitializedException($this->message);
+  }
+}
diff --git a/core/modules/simpletest/src/TestBase.php b/core/modules/simpletest/src/TestBase.php
index b4901af..a6d1bf2 100644
--- a/core/modules/simpletest/src/TestBase.php
+++ b/core/modules/simpletest/src/TestBase.php
@@ -1187,7 +1187,7 @@ private function prepareEnvironment() {
 
     // Ensure there is no service container.
     $this->container = NULL;
-    \Drupal::setContainer(NULL);
+    \Drupal::unsetContainer();
 
     // Unset globals.
     unset($GLOBALS['config_directories']);
diff --git a/core/modules/system/src/Tests/Bootstrap/GetFilenameUnitTest.php b/core/modules/system/src/Tests/Bootstrap/GetFilenameUnitTest.php
index a7bcca7..43dee4f 100644
--- a/core/modules/system/src/Tests/Bootstrap/GetFilenameUnitTest.php
+++ b/core/modules/system/src/Tests/Bootstrap/GetFilenameUnitTest.php
@@ -19,7 +19,7 @@ class GetFilenameUnitTest extends KernelTestBase {
   protected function setUp() {
     parent::setUp();
     $this->container = NULL;
-    \Drupal::setContainer(NULL);
+    \Drupal::unsetContainer();
   }
 
   /**
diff --git a/core/tests/Drupal/Tests/Core/DrupalContainerNotInitializedTest.php b/core/tests/Drupal/Tests/Core/DrupalContainerNotInitializedTest.php
new file mode 100644
index 0000000..5161e71
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/DrupalContainerNotInitializedTest.php
@@ -0,0 +1,156 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\Core\DrupalTest.
+ */
+
+namespace Drupal\Tests\Core;
+
+use Drupal\Core\DependencyInjection\ContainerNotInitializedException;
+use Drupal\Core\Url;
+
+/**
+ * Tests the case where Drupal::$container is not initialized.
+ *
+ * @group DrupalTest
+ */
+class DrupalContainerNotInitializedTest extends \PHPUnit_Framework_TestCase {
+
+  /**
+   * Tests the case where \Drupal::$container is not initialized.
+   *
+   * @dataProvider methodsWithReturnProvider
+   *
+   * @param string $method
+   *   The static method to call on \Drupal::
+   * @param mixed $expected
+   *   Expected return value.
+   * @param array $args
+   *   Arguments to pass into \Drupal::$method(..)
+   */
+  public function testContainerNotInitializedReturn($method, $expected, $args = array()) {
+    $result = call_user_func_array(['Drupal', $method], $args);
+    $this->assertEquals($expected, $result);
+  }
+
+  /**
+   * Tests the case where \Drupal::$container is not initialized.
+   *
+   * @dataProvider methodsWithExceptionProvider
+   *
+   * @param string $method
+   *   The static method to call on \Drupal::
+   * @param array $args
+   *   Arguments to pass into \Drupal::$method(..)
+   *
+   * @expectedException \Drupal\Core\DependencyInjection\ContainerNotInitializedException
+   * @expectedExceptionMessage \Drupal::$container is not initialized yet. \Drupal::setContainer() must be called with a real container.
+   */
+  public function testContainerNotInitializedException($method, $args = array()) {
+    call_user_func_array(['Drupal', $method], $args);
+  }
+
+  /**
+   * Tests the case where \Drupal::$container was unset.
+   *
+   * @dataProvider methodsWithReturnProvider
+   *
+   * @param string $method
+   *   The static method to call on \Drupal::
+   * @param mixed $expected
+   *   Expected return value.
+   * @param array $args
+   *   Arguments to pass into \Drupal::$method(..)
+   */
+  public function testUnsetContainerReturn($method, $expected, $args = array()) {
+    \Drupal::unsetContainer(__METHOD__);
+    $result = call_user_func_array(['Drupal', $method], $args);
+    $this->assertEquals($expected, $result);
+  }
+
+  /**
+   * Tests the case where \Drupal::$container was unset.
+   *
+   * @dataProvider methodsWithExceptionProvider
+   *
+   * @param string $method
+   *   The static method to call on \Drupal::
+   * @param array $args
+   *   Arguments to pass into \Drupal::$method(..)
+   *
+   * @expectedException \Drupal\Core\DependencyInjection\ContainerNotInitializedException
+   * @expectedExceptionMessage Custom exception message.
+   */
+  public function testUnsetContainerException($method, $args = array()) {
+    \Drupal::unsetContainer('Custom exception message.');
+    call_user_func_array(['Drupal', $method], $args);
+  }
+
+  /**
+   * Data provider for two methods, see "@see" below.
+   *
+   * @return array[]
+   *
+   * @see testContainerNotInitializedReturn()
+   * @see testUnsetContainerReturn()
+   */
+  public function methodsWithReturnProvider() {
+    return array(
+      ['getContainer', NULL],
+      ['hasService', FALSE, ['test_service']],
+      ['hasRequest', FALSE],
+    );
+  }
+
+  /**
+   * Data provider for two methods, see "@see" below.
+   *
+   * @return array[]
+   *
+   * @see testContainerNotInitializedException()
+   * @see testUnsetContainerException()
+   */
+  public function methodsWithExceptionProvider() {
+    return array(
+      ['service', ['test_service']],
+      ['request'],
+      ['requestStack'],
+      ['routeMatch'],
+      ['currentUser'],
+      ['entityManager'],
+      ['database'],
+      ['cache', ['test']],
+      ['keyValueExpirable', ['test_collection']],
+      ['lock'],
+      ['config', ['test_config']],
+      ['configFactory'],
+      ['queue', ['test_queue', TRUE]],
+      ['keyValue', ['test_collection']],
+      ['state'],
+      ['httpClient'],
+      ['entityQuery', ['OR']],
+      ['entityQueryAggregate', ['test_entity', 'OR']],
+      ['flood', ['test_service']],
+      ['moduleHandler', ['test_service']],
+      ['typedDataManager', ['test_service']],
+      ['token'],
+      ['urlGenerator'],
+      ['url', ['test_route']],
+      ['linkGenerator'],
+      ['l', ['Test title', new Url('test_route')]],
+      ['translation'],
+      ['languageManager'],
+      ['csrfToken'],
+      ['transliteration'],
+      ['formBuilder'],
+      ['theme'],
+      ['isConfigSyncing'],
+      ['logger', ['test_channel']],
+      ['menuTree'],
+      ['pathValidator'],
+      ['accessManager'],
+    );
+  }
+
+}
diff --git a/core/tests/Drupal/Tests/UnitTestCase.php b/core/tests/Drupal/Tests/UnitTestCase.php
index d6deb9e..e82c3a9 100644
--- a/core/tests/Drupal/Tests/UnitTestCase.php
+++ b/core/tests/Drupal/Tests/UnitTestCase.php
@@ -39,7 +39,7 @@ protected function setUp() {
     parent::setUp();
     // Ensure that an instantiated container in the global state of \Drupal from
     // a previous test does not leak into this test.
-    \Drupal::setContainer(NULL);
+    \Drupal::unsetContainer();
 
     $this->root = dirname(dirname(substr(__DIR__, 0, -strlen(__NAMESPACE__))));
   }
