diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index 2351ce3..a76e44f 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -23,7 +23,7 @@
 use Drupal\Core\Language\Language;
 use Drupal\Core\Lock\DatabaseLockBackend;
 use Drupal\Core\Lock\LockBackendInterface;
-use Drupal\Core\Session\UserSession;
+use Drupal\Core\Session\AnonymousUserSession;
 
 /**
  * @file
@@ -1323,23 +1323,13 @@ function drupal_get_messages($type = NULL, $clear_queue = TRUE) {
  *
  * @return \Drupal\Core\Session\AccountInterface
  *   The user session object.
+ *
+ * @deprecated in Drupal 8.x-dev. Will be removed before Drupal 8.0 by
+ *   https://drupal.org/node/2185315. Use
+ *   \Drupal\Core\Session\AnonymousUserSession.
  */
 function drupal_anonymous_user() {
-  try {
-    $request = \Drupal::request();
-    $hostname = $request->getClientIP();
-  }
-  catch (DependencyInjectionRuntimeException $e) {
-    // We are not in a request context.
-    $hostname = '';
-  }
-
-  $values = array(
-    'uid' => 0,
-    'hostname' => $hostname,
-    'roles' => array(DRUPAL_ANONYMOUS_RID),
-  );
-  return new UserSession($values);
+  return new AnonymousUserSession();
 }
 
 /**
@@ -1641,7 +1631,7 @@ function _drupal_bootstrap_page_cache() {
   // to serve a cached page.
   if (!$request->cookies->has(session_name()) && $cache_enabled) {
     // Make sure there is a user object because its timestamp will be checked.
-    $user = drupal_anonymous_user();
+    $user = new AnonymousUserSession();
     // Get the page from the cache.
     $cache = drupal_page_get_cache($request);
     // If there is a cached page, display it.
diff --git a/core/includes/common.inc b/core/includes/common.inc
index e6cc323..db0a04e 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -21,6 +21,7 @@
 use Drupal\Core\Routing\GeneratorNotInitializedException;
 use Drupal\Core\Template\Attribute;
 use Drupal\Core\Render\Element;
+use Drupal\Core\Session\AnonymousUserSession;
 
 /**
  * @file
diff --git a/core/includes/session.inc b/core/includes/session.inc
index 8e95036..3c480da 100644
--- a/core/includes/session.inc
+++ b/core/includes/session.inc
@@ -19,6 +19,7 @@
 use Drupal\Component\Utility\Crypt;
 use Drupal\Component\Utility\Settings;
 use Drupal\Core\Session\UserSession;
+use Drupal\Core\Session\AnonymousUserSession;
 use Drupal\Core\Utility\Error;
 
 /**
@@ -264,7 +265,7 @@ function drupal_session_initialize() {
     // processes (like drupal_get_token()) needs to know the future
     // session ID in advance.
     $GLOBALS['lazy_session'] = TRUE;
-    $user = drupal_anonymous_user();
+    $user = new AnonymousUserSession();
     // Less random sessions (which are much faster to generate) are used for
     // anonymous users than are generated in drupal_session_regenerate() when
     // a user becomes authenticated.
@@ -447,7 +448,7 @@ function _drupal_session_destroy($sid) {
   // Reset $_SESSION and $user to prevent a new session from being started
   // in drupal_session_commit().
   $_SESSION = array();
-  $user = drupal_anonymous_user();
+  $user = new AnonymousUserSession();
 
   // Unset the session cookies.
   _drupal_session_delete_cookie(session_name());
diff --git a/core/lib/Drupal/Core/Authentication/AuthenticationManager.php b/core/lib/Drupal/Core/Authentication/AuthenticationManager.php
index 672516a..1a7ca6e 100644
--- a/core/lib/Drupal/Core/Authentication/AuthenticationManager.php
+++ b/core/lib/Drupal/Core/Authentication/AuthenticationManager.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\Core\Authentication;
 
+use Drupal\Core\Session\AnonymousUserSession;
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Cmf\Component\Routing\RouteObjectInterface;
 use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
@@ -99,7 +100,7 @@ public function authenticate(Request $request) {
 
     // No provider returned a valid account, so set the user to anonymous.
     if (!$account) {
-      $account = drupal_anonymous_user();
+      $account = new AnonymousUserSession();
     }
 
     // No provider was fired, so assume the one with the least priority
diff --git a/core/lib/Drupal/Core/Cron.php b/core/lib/Drupal/Core/Cron.php
index 1fe9727..374d735 100644
--- a/core/lib/Drupal/Core/Cron.php
+++ b/core/lib/Drupal/Core/Cron.php
@@ -11,7 +11,7 @@
 use Drupal\Core\KeyValueStore\StateInterface;
 use Drupal\Core\Lock\LockBackendInterface;
 use Drupal\Core\Queue\QueueFactory;
-use Drupal\Core\Session\UserSession;
+use Drupal\Core\Session\AnonymousUserSession;
 
 /**
  * The Drupal core Cron service.
@@ -81,7 +81,7 @@ public function run() {
     // @todo This currently does not work, as it will not affect the current
     //   user being injected into services.
     $original_user = $GLOBALS['user'];
-    $GLOBALS['user'] = new UserSession();
+    $GLOBALS['user'] = new AnonymousUserSession();
 
     // Try to allocate enough time to run all the hook_cron implementations.
     drupal_set_time_limit(240);
diff --git a/core/lib/Drupal/Core/Routing/Enhancer/AuthenticationEnhancer.php b/core/lib/Drupal/Core/Routing/Enhancer/AuthenticationEnhancer.php
index 6e577b9..b9c477d 100644
--- a/core/lib/Drupal/Core/Routing/Enhancer/AuthenticationEnhancer.php
+++ b/core/lib/Drupal/Core/Routing/Enhancer/AuthenticationEnhancer.php
@@ -8,6 +8,7 @@
 namespace Drupal\Core\Routing\Enhancer;
 
 use Drupal\Core\Authentication\AuthenticationManagerInterface;
+use Drupal\Core\Session\AnonymousUserSession;
 use Symfony\Cmf\Component\Routing\Enhancer\RouteEnhancerInterface;
 use Symfony\Component\DependencyInjection\ContainerAware;
 use Symfony\Component\HttpFoundation\Request;
@@ -52,7 +53,7 @@ public function enhance(array $defaults, Request $request) {
       // If the request was authenticated with a non-permitted provider,
       // force the user back to anonymous.
       if (!in_array($auth_provider_triggered, $auth_providers)) {
-        $anonymous_user = drupal_anonymous_user();
+        $anonymous_user = new AnonymousUserSession();
 
         $this->container->set('current_user', $anonymous_user, 'request');
 
diff --git a/core/lib/Drupal/Core/Session/AccountInterface.php b/core/lib/Drupal/Core/Session/AccountInterface.php
index 2c23cda..78e8ebe 100644
--- a/core/lib/Drupal/Core/Session/AccountInterface.php
+++ b/core/lib/Drupal/Core/Session/AccountInterface.php
@@ -152,4 +152,11 @@ public function getTimeZone();
    */
   public function getLastAccessedTime();
 
+  /**
+   * Returns the session hostname.
+   *
+   * @return string
+   */
+  public function getHostname();
+
 }
diff --git a/core/lib/Drupal/Core/Session/AnonymousUserSession.php b/core/lib/Drupal/Core/Session/AnonymousUserSession.php
new file mode 100644
index 0000000..56e065c
--- /dev/null
+++ b/core/lib/Drupal/Core/Session/AnonymousUserSession.php
@@ -0,0 +1,26 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Session\AnonymousUserSession.
+ */
+
+namespace Drupal\Core\Session;
+
+/**
+ * An account implementation representing an anonymous user.
+ */
+class AnonymousUserSession extends UserSession {
+
+  /**
+   * Constructs a new anonymous user session.
+   *
+   * Intentionally don't allow parameters to be passed in like UserSession.
+   */
+  public function __construct() {
+    if (\Drupal::hasRequest()) {
+      $this->hostname = \Drupal::request()->getClientIp();
+    }
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Session/UserSession.php b/core/lib/Drupal/Core/Session/UserSession.php
index af33674..bfaefcc 100644
--- a/core/lib/Drupal/Core/Session/UserSession.php
+++ b/core/lib/Drupal/Core/Session/UserSession.php
@@ -94,10 +94,17 @@ class UserSession implements AccountInterface {
   protected $timezone;
 
   /**
+   * The hostname for this user session.
+   *
+   * @var string
+   */
+  protected $hostname = '';
+
+  /**
    * Constructs a new user session.
    *
    * @param array $values
-   *   Array of initial values for the user sesion.
+   *   Array of initial values for the user session.
    */
   public function __construct(array $values = array()) {
     foreach ($values as $key => $value) {
@@ -230,4 +237,11 @@ public function getLastAccessedTime() {
     return $this->timestamp;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getHostname() {
+    return $this->hostname;
+  }
+
 }
diff --git a/core/modules/comment/lib/Drupal/comment/Plugin/Field/FieldType/CommentItem.php b/core/modules/comment/lib/Drupal/comment/Plugin/Field/FieldType/CommentItem.php
index 115bce2..f5f4a65 100644
--- a/core/modules/comment/lib/Drupal/comment/Plugin/Field/FieldType/CommentItem.php
+++ b/core/modules/comment/lib/Drupal/comment/Plugin/Field/FieldType/CommentItem.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Field\FieldDefinitionInterface;
 use Drupal\Core\TypedData\DataDefinition;
 use Drupal\Core\Field\FieldItemBase;
+use Drupal\Core\Session\AnonymousUserSession;
 
 /**
  * Plugin implementation of the 'comment' field type.
@@ -91,6 +92,7 @@ public function instanceSettingsForm(array $form, array &$form_state) {
 
     $entity_type = $this->getEntity()->getEntityTypeId();
     $field_name = $this->getFieldDefinition()->getName();
+    $anonymous_user = new AnonymousUserSession();
 
     $element['comment'] = array(
       '#type' => 'details',
@@ -126,7 +128,7 @@ public function instanceSettingsForm(array $form, array &$form_state) {
         COMMENT_ANONYMOUS_MAY_CONTACT => t('Anonymous posters may leave their contact information'),
         COMMENT_ANONYMOUS_MUST_CONTACT => t('Anonymous posters must leave their contact information'),
       ),
-      '#access' => drupal_anonymous_user()->hasPermission('post comments'),
+      '#access' => $anonymous_user->hasPermission('post comments'),
     );
     $element['comment']['subject'] = array(
       '#type' => 'checkbox',
diff --git a/core/modules/contact/lib/Drupal/contact/MessageFormController.php b/core/modules/contact/lib/Drupal/contact/MessageFormController.php
index 143225b..122665f 100644
--- a/core/modules/contact/lib/Drupal/contact/MessageFormController.php
+++ b/core/modules/contact/lib/Drupal/contact/MessageFormController.php
@@ -146,8 +146,8 @@ public function save(array $form, array &$form_state) {
 
     $sender = clone user_load($user->id());
     if ($user->isAnonymous()) {
-      // At this point, $sender contains drupal_anonymous_user(), so we need to
-      // take over the submitted form values.
+      // At this point, $sender contains an anonymous user, so we need to take
+      // over the submitted form values.
       $sender->name = $message->getSenderName();
       $sender->mail = $message->getSenderMail();
       // Save the anonymous user information to a cookie for reuse.
diff --git a/core/modules/filter/lib/Drupal/filter/Tests/FilterAPITest.php b/core/modules/filter/lib/Drupal/filter/Tests/FilterAPITest.php
index c36b009..bfd6672 100644
--- a/core/modules/filter/lib/Drupal/filter/Tests/FilterAPITest.php
+++ b/core/modules/filter/lib/Drupal/filter/Tests/FilterAPITest.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\filter\Tests;
 
+use Drupal\Core\Session\AnonymousUserSession;
 use Drupal\Core\TypedData\AllowedValuesInterface;
 use Drupal\Core\TypedData\DataDefinition;
 use Drupal\filter\Plugin\DataType\FilterFormat;
@@ -205,7 +206,7 @@ function testTypedDataAPI() {
     ));
 
     // Test with anonymous user.
-    $user = drupal_anonymous_user();
+    $user = new AnonymousUserSession();
     $this->container->set('current_user', $user);
 
     $expected_available_options = array(
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
index 8efa40a..3f86126 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
@@ -16,6 +16,7 @@
 use Drupal\Core\Database\ConnectionNotDefinedException;
 use Drupal\Core\Language\Language;
 use Drupal\Core\Session\AccountInterface;
+use Drupal\Core\Session\AnonymousUserSession;
 use Drupal\Core\Session\UserSession;
 use Drupal\Core\StreamWrapper\PublicStream;
 use Drupal\Core\Datetime\DrupalDateTime;
@@ -728,7 +729,7 @@ protected function drupalLogout() {
       // @see WebTestBase::drupalUserIsLoggedIn()
       unset($this->loggedInUser->session_id);
       $this->loggedInUser = FALSE;
-      $this->container->set('current_user', drupal_anonymous_user());
+      $this->container->set('current_user', new AnonymousUserSession());
     }
   }
 
diff --git a/core/modules/user/lib/Drupal/user/Entity/User.php b/core/modules/user/lib/Drupal/user/Entity/User.php
index 8cac65c..15fde70 100644
--- a/core/modules/user/lib/Drupal/user/Entity/User.php
+++ b/core/modules/user/lib/Drupal/user/Entity/User.php
@@ -54,6 +54,13 @@
 class User extends ContentEntityBase implements UserInterface {
 
   /**
+   * The hostname for this user.
+   *
+   * @var string
+   */
+  protected $hostname;
+
+  /**
    * {@inheritdoc}
    */
   public function id() {
@@ -196,6 +203,17 @@ public function getSessionId() {
   /**
    * {@inheritdoc}
    */
+  public function getHostname() {
+    if (!isset($this->hostname) && \Drupal::hasRequest()) {
+      $this->hostname = \Drupal::request()->getClientIp();
+    }
+
+    return $this->hostname;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function hasRole($rid) {
     return in_array($rid, $this->getRoles());
   }
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index c1005d3..8c75c76 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -4,6 +4,7 @@
 use Drupal\Core\Cache\Cache;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Session\AccountInterface;
+use Drupal\Core\Session\AnonymousUserSession;
 use \Drupal\Core\Entity\Display\EntityViewDisplayInterface;
 use Drupal\file\Entity\File;
 use Drupal\user\Entity\User;
@@ -180,6 +181,7 @@ function user_attach_accounts(array $entities) {
   $uids = array_unique($uids);
   $accounts = user_load_multiple($uids);
   $anonymous = entity_create('user', array('uid' => 0));
+
   foreach ($entities as $id => $entity) {
     if (isset($accounts[$entity->getOwnerId()])) {
       $entities[$id]->setOwner($accounts[$entity->getOwnerId()]);
@@ -610,7 +612,7 @@ function user_template_preprocess_default_variables_alter(&$variables) {
  * check_plain() or filter_xss().
  */
 function template_preprocess_username(&$variables) {
-  $account = $variables['account'] ?: drupal_anonymous_user();
+  $account = $variables['account'] ?: new AnonymousUserSession();
 
   $variables['extra'] = '';
   $variables['uid'] = $account->id();
@@ -1021,7 +1023,7 @@ function _user_cancel($edit, $account, $method) {
   // regenerate it because batch API uses the session ID, we will regenerate it
   // in _user_cancel_session_regenerate().
   if ($account->id() == $user->id()) {
-    $user = drupal_anonymous_user();
+    $user = new AnonymousUserSession();
   }
 
   // Clear the cache for anonymous users.
diff --git a/core/tests/Drupal/Tests/Core/Session/AnonymousUserSessionTest.php b/core/tests/Drupal/Tests/Core/Session/AnonymousUserSessionTest.php
new file mode 100644
index 0000000..6d1f130
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/Session/AnonymousUserSessionTest.php
@@ -0,0 +1,77 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\Core\Session\AnonymousUserSessionTest.
+ */
+
+namespace Drupal\Tests\Core\Session;
+
+use Drupal\Tests\UnitTestCase;
+use Drupal\Core\Session\AnonymousUserSession;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Definition;
+use Symfony\Component\DependencyInjection\Scope;
+
+/**
+ * Tests the AnonymousUserSession class.
+ *
+ * @group Drupal
+ *
+ * @coversDefaultClass \Drupal\Core\Session\AnonymousUserSession
+ */
+class AnonymousUserSessionTest extends UnitTestCase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Anonymous user session object',
+      'description' => 'Tests the anonymous user session object.',
+      'group' => 'Session',
+    );
+  }
+
+  /**
+   * Tests creating an AnonymousUserSession when the request is available.
+   *
+   * @covers ::__construct()
+   */
+  public function testAnonymousUserSessionWithRequest() {
+    $request = $this->getMock('Symfony\Component\HttpFoundation\Request');
+    $request->expects($this->once())
+      ->method('getClientIp')
+      ->will($this->returnValue('test'));
+    $container = new ContainerBuilder();
+    $container->addScope(new Scope('request'));
+    $container->enterScope('request');
+    $container->set('request', $request, 'request');
+    \Drupal::setContainer($container);
+
+    $anonymous_user = new AnonymousUserSession();
+
+    $this->assertSame('test', $anonymous_user->getHostname());
+  }
+
+  /**
+   * Tests creating an AnonymousUserSession when the request is not available.
+   *
+   * @covers ::__construct()
+   */
+  public function testAnonymousUserSessionWithNoRequest() {
+    $container = new ContainerBuilder();
+
+    // Set a synthetic 'request' definition on the container.
+    $definition = new Definition();
+    $definition->setSynthetic(TRUE);
+
+    $container->setDefinition('request', $definition);
+    \Drupal::setContainer($container);
+
+    $anonymous_user = new AnonymousUserSession();
+
+    $this->assertSame('', $anonymous_user->getHostname());
+  }
+
+}
