diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index 8bbdd91..9c720ab 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -22,7 +22,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
@@ -1679,30 +1679,6 @@ function drupal_set_title($title = NULL, $output = Title::CHECK_PLAIN) {
 }
 
 /**
- * Generates a default anonymous $user object.
- *
- * @return \Drupal\Core\Session\AccountInterface
- *   The user session object.
- */
-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);
-}
-
-/**
  * Ensures Drupal is bootstrapped to the specified phase.
  *
  * In order to bootstrap Drupal from another PHP script, you can use this code:
@@ -1996,7 +1972,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 fa9ec08..0e6eb71 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -21,6 +21,7 @@
 use Drupal\Core\SystemListingInfo;
 use Drupal\Core\Template\Attribute;
 use Drupal\Core\Render\Element;
+use Drupal\Core\Session\AnonymousUserSession;
 
 /**
  * @file
@@ -3196,7 +3197,7 @@ function drupal_cron_run() {
   // Force the current user to anonymous to ensure consistent permissions on
   // cron runs.
   $original_user = $GLOBALS['user'];
-  $GLOBALS['user'] = drupal_anonymous_user();
+  $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/includes/session.inc b/core/includes/session.inc
index fa46972..ab4516b 100644
--- a/core/includes/session.inc
+++ b/core/includes/session.inc
@@ -18,6 +18,7 @@
 
 use Drupal\Component\Utility\Crypt;
 use Drupal\Core\Session\UserSession;
+use Drupal\Core\Session\AnonymousUserSession;
 use Drupal\Core\Utility\Error;
 
 /**
@@ -260,7 +261,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.
@@ -443,7 +444,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 d3630c4..ed1fb16 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/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..661b0c4
--- /dev/null
+++ b/core/lib/Drupal/Core/Session/AnonymousUserSession.php
@@ -0,0 +1,31 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Session\AnonymousUserSession.
+ */
+
+namespace Drupal\Core\Session;
+
+use Symfony\Component\DependencyInjection\Exception\RuntimeException;
+
+/**
+ *
+ */
+class AnonymousUserSession extends UserSession {
+
+  /**
+   * Constructs a new anonymous user session.
+   *
+   * Intentionally don't allow parameters to be passed in like UserSession.
+   */
+  public function __construct() {
+    try {
+      $this->hostname = \Drupal::request()->getClientIp();
+    }
+    catch (RuntimeException $e) {
+      // We are not in a request context.
+    }
+  }
+
+}
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 3145e8f..c543d5a 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\TypedData\DataDefinition;
 use Drupal\Core\Field\FieldDefinitionInterface;
 use Drupal\Core\Field\ConfigFieldItemBase;
+use Drupal\Core\Session\AnonymousUserSession;
 
 /**
  * Plugin implementation of the 'comment' field type.
@@ -96,6 +97,7 @@ public function instanceSettingsForm(array $form, array &$form_state) {
 
     $entity_type = $this->getEntity()->entityType();
     $field_name = $this->getFieldDefinition()->getName();
+    $anonymous_user = new AnonymousUserSession();
 
     $element['comment'] = array(
       '#type' => 'details',
@@ -132,7 +134,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 ca4a607..952a405 100644
--- a/core/modules/contact/lib/Drupal/contact/MessageFormController.php
+++ b/core/modules/contact/lib/Drupal/contact/MessageFormController.php
@@ -138,8 +138,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 6d39f41..d171c3f 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;
@@ -202,7 +203,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/TestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php
index 78b154e8..ba81d9f 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php
@@ -17,6 +17,7 @@
 use Drupal\Core\Config\StorageInterface;
 use Drupal\Core\DrupalKernel;
 use Drupal\Core\Language\Language;
+use Drupal\Core\Session\AnonymousUserSession;
 use Drupal\Core\StreamWrapper\PublicStream;
 use Drupal\Core\Utility\Error;
 use Symfony\Component\HttpFoundation\Request;
@@ -963,7 +964,7 @@ private function prepareEnvironment() {
     drupal_save_session(FALSE);
     // Run all tests as a anonymous user by default, web tests will replace that
     // during the test set up.
-    $user = drupal_anonymous_user();
+    $user = new AnonymousUserSession();
 
     // Save and clean the shutdown callbacks array because it is static cached
     // and will be changed by the test run. Otherwise it will contain callbacks
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
index 9d17cac..2b7c2db 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
@@ -15,6 +15,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;
@@ -691,7 +692,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 2954df5..e4c1b57 100644
--- a/core/modules/user/lib/Drupal/user/Entity/User.php
+++ b/core/modules/user/lib/Drupal/user/Entity/User.php
@@ -196,6 +196,13 @@ public function getSessionId() {
   /**
    * {@inheritdoc}
    */
+  public function getHostname() {
+    return NULL;
+  }
+
+  /**
+   * {@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 8cb2810..c9215c8 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -3,6 +3,7 @@
 use Drupal\Component\Utility\Crypt;
 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;
@@ -171,7 +172,7 @@ function user_attach_accounts(array $entities) {
   }
   $uids = array_unique($uids);
   $accounts = user_load_multiple($uids);
-  $anonymous = drupal_anonymous_user();
+  $anonymous = new AnonymousUserSession();
   foreach ($entities as $id => $entity) {
     if (isset($accounts[$entity->getAuthorId()])) {
       $entities[$id]->account = $accounts[$entity->getAuthorId()];
@@ -599,7 +600,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();
@@ -1183,7 +1184,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/scripts/generate-d7-content.sh b/core/scripts/generate-d7-content.sh
index 30c61a2..04e7ea4 100644
--- a/core/scripts/generate-d7-content.sh
+++ b/core/scripts/generate-d7-content.sh
@@ -261,7 +261,7 @@
   for ($v = 0; $v < ($i % 4); $v++) {
     drupal_static_reset('ip_address');
     $_SERVER['REMOTE_ADDR'] = "127.0.$v.1";
-    $GLOBALS['user'] = drupal_anonymous_user();// We should have already allowed anon to vote.
+    $GLOBALS['user'] = new \Drupal\Core\Session\AnonymousUserSession();// We should have already allowed anon to vote.
     $c = $v % $nbchoices;
     $form_state = array();
     $form_state['values']['choice'] = $choices[$c];
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..82b2496
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/Session/AnonymousUserSessionTest.php
@@ -0,0 +1,74 @@
+<?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;
+
+/**
+ * Tests the AnonymousUserSession class.
+ *
+ * @group Drupal
+ *
+ * @see \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 \Drupal\Core\Session\AnonymousUserSession::__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->set('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 \Drupal\Core\Session\AnonymousUserSession::__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());
+  }
+
+}
