diff --git a/core/modules/path/path.module b/core/modules/path/path.module
index 182c6a9..2ee45ba 100644
--- a/core/modules/path/path.module
+++ b/core/modules/path/path.module
@@ -4,7 +4,7 @@
  * @file
  * Enables users to rename URLs.
  */
-
+use Drupal\Core\Entity\ContentEntityInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Field\BaseFieldDefinition;
 use Drupal\Core\Form\FormStateInterface;
@@ -76,3 +76,17 @@ function path_entity_base_field_info(EntityTypeInterface $entity_type) {
     return $fields;
   }
 }
+
+/**
+ * Implements hook_entity_translation_create().
+ */
+function path_entity_translation_create(ContentEntityInterface $translation) {
+  foreach ($translation->getFieldDefinitions() as $field_name => $field_definition) {
+    if ($field_definition->getType() == 'path' && $translation->get($field_name)->pid) {
+      // If there are values and a PID, update the langcode and unset the pid
+      // to save this as a new alisa.
+      $translation->get($field_name)->langcode = $translation->language()->getId();
+      $translation->get($field_name)->pid = NULL;
+    }
+  }
+}
diff --git a/core/modules/path/src/Plugin/Field/FieldType/PathFieldItemList.php b/core/modules/path/src/Plugin/Field/FieldType/PathFieldItemList.php
index ee03361..52db66b 100644
--- a/core/modules/path/src/Plugin/Field/FieldType/PathFieldItemList.php
+++ b/core/modules/path/src/Plugin/Field/FieldType/PathFieldItemList.php
@@ -34,4 +34,34 @@ public function delete() {
     \Drupal::service('path.alias_storage')->delete($conditions);
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getValue($include_computed = FALSE) {
+    $this->ensureLoaded();
+    return parent::getValue($include_computed);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isEmpty() {
+    $this->ensureLoaded();
+    return parent::isEmpty();
+  }
+
+  /**
+   * Automatically create the first item for computed fields.
+   *
+   * This ensures that ::getValue() and ::isEmpty() calls will behave like a
+   * non-computed field.
+   *
+   * @todo: Move this to the base class in https://www.drupal.org/node/2392845.
+   */
+  protected function ensureLoaded() {
+    if (!isset($this->list[0]) && $this->definition->isComputed()) {
+      $this->list[0] = $this->createItem(0);
+    }
+  }
+
 }
diff --git a/core/modules/path/src/Plugin/Field/FieldType/PathItem.php b/core/modules/path/src/Plugin/Field/FieldType/PathItem.php
index 239588f..ff8d795 100644
--- a/core/modules/path/src/Plugin/Field/FieldType/PathItem.php
+++ b/core/modules/path/src/Plugin/Field/FieldType/PathItem.php
@@ -23,6 +23,13 @@
 class PathItem extends FieldItemBase {
 
   /**
+   * Whether the alias has been loaded from the alias storage service yet.
+   *
+   * @var bool
+   */
+  protected $isLoaded = FALSE;
+
+  /**
    * {@inheritdoc}
    */
   public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
@@ -30,12 +37,22 @@ public static function propertyDefinitions(FieldStorageDefinitionInterface $fiel
       ->setLabel(t('Path alias'));
     $properties['pid'] = DataDefinition::create('integer')
       ->setLabel(t('Path id'));
+    $properties['langcode'] = DataDefinition::create('string')
+      ->setLabel(t('Language Code'));
     return $properties;
   }
 
   /**
    * {@inheritdoc}
    */
+  public function __get($name) {
+    $this->ensureLoaded();
+    return parent::__get($name);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public static function schema(FieldStorageDefinitionInterface $field_definition) {
     return array();
   }
@@ -43,6 +60,22 @@ public static function schema(FieldStorageDefinitionInterface $field_definition)
   /**
    * {@inheritdoc}
    */
+  public function getValue() {
+    $this->ensureLoaded();
+    return parent::getValue();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isEmpty() {
+    $this->ensureLoaded();
+    return parent::isEmpty();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function preSave() {
     $this->alias = trim($this->alias);
   }
@@ -88,4 +121,38 @@ public static function mainPropertyName() {
     return 'alias';
   }
 
+  /**
+   * Ensures the alias properties are loaded if available.
+   *
+   * This ensures that the properties will always be loaded and act like
+   * non-computed fields when calling ::__get() and getValue().
+   *
+   * @todo: Determine if this should be moved to the base class in
+   *   https://www.drupal.org/node/2392845.
+   */
+  protected function ensureLoaded() {
+    if (!$this->isLoaded) {
+      $entity = $this->getEntity();
+      if (!$entity->isNew()) {
+        // @todo Support loading languge neutral aliases in
+        //   https://www.drupal.org/node/2511968.
+        $alias = \Drupal::service('path.alias_storage')->load([
+          'source' => '/' . $entity->toUrl()->getInternalPath(),
+          'langcode' => $this->getLangcode(),
+        ]);
+        if ($alias) {
+          $this->setValue($alias);
+        }
+        else {
+          // If there is no existing alias, default the langcode to the current
+          // language.
+          // @todo Set the langcode to not specified for untranslatable fields
+          //   in https://www.drupal.org/node/2689459.
+          $this->langcode = $this->getLangcode();
+        }
+      }
+      $this->isLoaded = TRUE;
+    }
+  }
+
 }
diff --git a/core/modules/path/src/Plugin/Field/FieldWidget/PathWidget.php b/core/modules/path/src/Plugin/Field/FieldWidget/PathWidget.php
index 366db88..e5b71c6 100644
--- a/core/modules/path/src/Plugin/Field/FieldWidget/PathWidget.php
+++ b/core/modules/path/src/Plugin/Field/FieldWidget/PathWidget.php
@@ -5,7 +5,6 @@
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\WidgetBase;
 use Drupal\Core\Form\FormStateInterface;
-use Drupal\Core\Language\LanguageInterface;
 use Symfony\Component\Validator\ConstraintViolationInterface;
 
 /**
@@ -26,23 +25,6 @@ class PathWidget extends WidgetBase {
    */
   public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
     $entity = $items->getEntity();
-    $path = array();
-    if (!$entity->isNew()) {
-      $conditions = array('source' => '/' . $entity->urlInfo()->getInternalPath());
-      if ($items->getLangcode() != LanguageInterface::LANGCODE_NOT_SPECIFIED) {
-        $conditions['langcode'] = $items->getLangcode();
-      }
-      $path = \Drupal::service('path.alias_storage')->load($conditions);
-      if ($path === FALSE) {
-        $path = array();
-      }
-    }
-    $path += array(
-      'pid' => NULL,
-      'source' => !$entity->isNew() ? '/' . $entity->urlInfo()->getInternalPath() : NULL,
-      'alias' => '',
-      'langcode' => $items->getLangcode(),
-    );
 
     $element += array(
       '#element_validate' => array(array(get_class($this), 'validateFormElement')),
@@ -50,22 +32,22 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
     $element['alias'] = array(
       '#type' => 'textfield',
       '#title' => $element['#title'],
-      '#default_value' => $path['alias'],
+      '#default_value' => $items[$delta]->alias,
       '#required' => $element['#required'],
       '#maxlength' => 255,
       '#description' => $this->t('Specify an alternative path by which this data can be accessed. For example, type "/about" when writing an about page.'),
     );
     $element['pid'] = array(
       '#type' => 'value',
-      '#value' => $path['pid'],
+      '#value' => $items[$delta]->pid,
     );
     $element['source'] = array(
       '#type' => 'value',
-      '#value' => $path['source'],
+      '#value' => !$entity->isNew() ? '/' . $entity->toUrl()->getInternalPath() : NULL,
     );
     $element['langcode'] = array(
       '#type' => 'value',
-      '#value' => $path['langcode'],
+      '#value' => $items[$delta]->langcode,
     );
     return $element;
   }
diff --git a/core/modules/path/tests/src/Functional/NodeJsonPathTest.php b/core/modules/path/tests/src/Functional/NodeJsonPathTest.php
new file mode 100644
index 0000000..64a4549
--- /dev/null
+++ b/core/modules/path/tests/src/Functional/NodeJsonPathTest.php
@@ -0,0 +1,52 @@
+<?php
+
+namespace Drupal\Tests\path\Functional;
+
+use Drupal\Tests\rest\Functional\EntityResource\Node\NodeJsonCookieTest;
+
+/**
+ *
+ * Test that path aliases are correctly exported with REST.
+ *
+ * @group rest
+ */
+class NodeJsonPathTest extends NodeJsonCookieTest {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = ['path'];
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setUp() {
+    parent::setUp();
+    static::$patchProtectedFieldNames[] = 'path';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function createEntity() {
+    $node = parent::createEntity();
+    $node->path->alias = '/llama';
+    $node->save();
+    return $node;
+  }
+
+  protected function getExpectedNormalizedEntity() {
+    $expected = parent::getExpectedNormalizedEntity();
+    $expected['path'] = [
+      [
+        'alias' => '/llama',
+        'pid' => '1',
+        'langcode' => 'en',
+      ],
+    ];
+    return $expected;
+  }
+
+}
diff --git a/core/modules/path/tests/src/Kernel/PathItemTest.php b/core/modules/path/tests/src/Kernel/PathItemTest.php
new file mode 100644
index 0000000..1d694d7
--- /dev/null
+++ b/core/modules/path/tests/src/Kernel/PathItemTest.php
@@ -0,0 +1,137 @@
+<?php
+
+namespace Drupal\Tests\path\Kernel;
+
+use Drupal\KernelTests\KernelTestBase;
+use Drupal\language\Entity\ConfigurableLanguage;
+use Drupal\node\Entity\Node;
+use Drupal\node\Entity\NodeType;
+
+/**
+ * Tests loading and storing data using PathItem.
+ *
+ * @group path
+ */
+class PathItemTest extends KernelTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = ['path', 'node', 'user', 'system', 'language', 'content_translation'];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    $this->installEntitySchema('node');
+    $this->installEntitySchema('user');
+
+    $this->installSchema('node', ['node_access']);
+
+    $node_type = NodeType::create(['type' => 'foo']);
+    $node_type->save();
+
+    $this->installConfig(['language']);
+    ConfigurableLanguage::createFromLangcode('de')->save();
+  }
+
+  /**
+   * Test creating, loading, updating and deleting aliases through PathItem.
+   */
+  public function testPathItem() {
+
+    /** @var \Drupal\Core\Path\AliasStorageInterface $alias_storage */
+    $alias_storage = \Drupal::service('path.alias_storage');
+
+    $node_storage = \Drupal::entityTypeManager()->getStorage('node');
+
+    $node = Node::create([
+      'title' => 'Testing create()',
+      'type' => 'foo',
+      'path' => ['alias' => '/foo'],
+    ]);
+    $this->assertFalse($node->get('path')->isEmpty());
+    $this->assertEquals('/foo', $node->get('path')->alias);
+
+    $node->save();
+    $this->assertFalse($node->get('path')->isEmpty());
+    $this->assertEquals('/foo', $node->get('path')->alias);
+
+    $stored_alias = $alias_storage->lookupPathAlias('/' . $node->toUrl()->getInternalPath(), $node->language()->getId());
+    $this->assertEquals('/foo', $stored_alias);
+
+    $node_storage->resetCache();
+
+    /** @var \Drupal\node\NodeInterface $loaded_node */
+    $loaded_node = $node_storage->load($node->id());
+    $this->assertFalse($loaded_node->get('path')->isEmpty());
+    $this->assertEquals('/foo', $loaded_node->get('path')->alias);
+
+    $node_storage->resetCache();
+    $loaded_node = $node_storage->load($node->id());
+    $values = $loaded_node->get('path')->getValue();
+    $this->assertEquals('/foo', $values[0]['alias']);
+
+    $node_storage->resetCache();
+    $loaded_node = $node_storage->load($node->id());
+    $this->assertEquals('/foo', $loaded_node->path->alias);
+
+    // Add a translation, verify it is being saved as expected.
+    $translation = $loaded_node->addTranslation('de', $loaded_node->toArray());
+    $translation->get('path')->alias = '/furchtbar';
+    $translation->save();
+
+    // Assert the alias on the English node, the German translation and the
+    // stored aliases.
+    $node_storage->resetCache();
+    $loaded_node = $node_storage->load($node->id());
+    $this->assertEquals('/foo', $loaded_node->path->alias);
+    $translation = $loaded_node->getTranslation('de');
+    $this->assertEquals('/furchtbar', $translation->path->alias);
+
+    $stored_alias = $alias_storage->lookupPathAlias('/' . $node->toUrl()->getInternalPath(), $node->language()->getId());
+    $this->assertEquals('/foo', $stored_alias);
+    $stored_alias = $alias_storage->lookupPathAlias('/' . $node->toUrl()->getInternalPath(), $translation->language()->getId());
+    $this->assertEquals('/furchtbar', $stored_alias);
+
+    $loaded_node->get('path')->alias = '/bar';
+    $this->assertFalse($loaded_node->get('path')->isEmpty());
+    $this->assertEquals('/bar', $loaded_node->get('path')->alias);
+
+    $loaded_node->save();
+    $this->assertFalse($loaded_node->get('path')->isEmpty());
+    $this->assertEquals('/bar', $loaded_node->get('path')->alias);
+
+    $node_storage->resetCache();
+    $loaded_node = $node_storage->load($node->id());
+    $this->assertFalse($loaded_node->get('path')->isEmpty());
+    $this->assertEquals('/bar', $loaded_node->get('path')->alias);
+
+    $loaded_node->get('path')->alias = '/bar';
+    $this->assertFalse($loaded_node->get('path')->isEmpty());
+    $this->assertEquals('/bar', $loaded_node->get('path')->alias);
+
+    $loaded_node->save();
+    $this->assertFalse($loaded_node->get('path')->isEmpty());
+    $this->assertEquals('/bar', $loaded_node->get('path')->alias);
+
+    $stored_alias = $alias_storage->lookupPathAlias('/' . $node->toUrl()->getInternalPath(), $node->language()->getId());
+    $this->assertEquals('/bar', $stored_alias);
+
+    $old_alias = $alias_storage->lookupPathSource('/foo', $node->language()->getId());
+    $this->assertFalse($old_alias);
+
+    $loaded_node->get('path')->alias = '';
+    $this->assertEquals('', $loaded_node->get('path')->alias);
+
+    $loaded_node->save();
+
+    $stored_alias = $alias_storage->lookupPathAlias('/' . $node->toUrl()->getInternalPath(), $node->language()->getId());
+    $this->assertFalse($stored_alias);
+  }
+
+}
