diff --git a/core/lib/Drupal/Core/Entity/ContentEntityBase.php b/core/lib/Drupal/Core/Entity/ContentEntityBase.php
index 9d0e5d63b10398d581ef51756c1d51f113a5b45d..f554197c635ca741eaf6ef49e1b7343244e98bfe 100644
--- a/core/lib/Drupal/Core/Entity/ContentEntityBase.php
+++ b/core/lib/Drupal/Core/Entity/ContentEntityBase.php
@@ -138,12 +138,19 @@ abstract class ContentEntityBase extends Entity implements \IteratorAggregate, C
   protected $isDefaultRevision = TRUE;
 
   /**
-   * Holds entity keys like the ID, bundle and revision ID.
+   * Holds translatable entity keys such as the ID, bundle and revision ID.
    *
    * @var array
    */
   protected $entityKeys = array();
 
+  /**
+   * Holds translatable entity keys such as the label.
+   *
+   * @var array
+   */
+  protected $translatableEntityKeys = array();
+
   /**
    * Overrides Entity::__construct().
    */
@@ -165,14 +172,36 @@ public function __construct(array $values, $entity_type, $bundle = FALSE, $trans
     $this->values = $values;
     foreach ($this->getEntityType()->getKeys() as $key => $field_name) {
       if (isset($this->values[$field_name])) {
-        if (is_array($this->values[$field_name]) && isset($this->values[$field_name][LanguageInterface::LANGCODE_DEFAULT])) {
-          if (is_array($this->values[$field_name][LanguageInterface::LANGCODE_DEFAULT])) {
-            if (isset($this->values[$field_name][LanguageInterface::LANGCODE_DEFAULT][0]['value'])) {
-              $this->entityKeys[$key] = $this->values[$field_name][LanguageInterface::LANGCODE_DEFAULT][0]['value'];
+        if (is_array($this->values[$field_name])) {
+          // We store untranslatable fields into an entity key without using a
+          // langcode key.
+          if (!$this->getFieldDefinition($field_name)->isTranslatable()) {
+            if (isset($this->values[$field_name][LanguageInterface::LANGCODE_DEFAULT])) {
+              if (is_array($this->values[$field_name][LanguageInterface::LANGCODE_DEFAULT])) {
+                if (isset($this->values[$field_name][LanguageInterface::LANGCODE_DEFAULT][0]['value'])) {
+                  $this->entityKeys[$key] = $this->values[$field_name][LanguageInterface::LANGCODE_DEFAULT][0]['value'];
+                }
+              }
+              else {
+                $this->entityKeys[$key] = $this->values[$field_name][LanguageInterface::LANGCODE_DEFAULT];
+              }
             }
           }
           else {
-            $this->entityKeys[$key] = $this->values[$field_name][LanguageInterface::LANGCODE_DEFAULT];
+            // We save translatable fields such as the publishing status of a node
+            // into an entity key array keyed by langcode as a performance
+            // optimization, so we don't have to go through TypedData when we
+            // need these values.
+            foreach ($this->values[$field_name] as $langcode => $field_value) {
+              if (is_array($this->values[$field_name][$langcode])) {
+                if (isset($this->values[$field_name][$langcode][0]['value'])) {
+                  $this->translatableEntityKeys[$key][$langcode] = $this->values[$field_name][$langcode][0]['value'];
+                }
+              }
+              else {
+                $this->translatableEntityKeys[$key][$langcode] = $this->values[$field_name][$langcode];
+              }
+            }
           }
         }
       }
@@ -537,12 +566,12 @@ protected function setDefaultLangcode() {
     // Get the language code if the property exists.
     // Try to read the value directly from the list of entity keys which got
     // initialized in __construct(). This avoids creating a field item object.
-    if (isset($this->entityKeys['langcode'])) {
-      $this->defaultLangcode = $this->entityKeys['langcode'];
+    if (isset($this->translatableEntityKeys['langcode'][$this->activeLangcode])) {
+      $this->defaultLangcode = $this->translatableEntityKeys['langcode'][$this->activeLangcode];
     }
     elseif ($this->hasField($this->langcodeKey) && ($item = $this->get($this->langcodeKey)) && isset($item->language)) {
       $this->defaultLangcode = $item->language->getId();
-      $this->entityKeys['langcode'] = $this->defaultLangcode;
+      $this->translatableEntityKeys['langcode'][$this->activeLangcode] = $this->defaultLangcode;
     }
 
     if (empty($this->defaultLangcode)) {
@@ -583,8 +612,13 @@ public function onChange($name) {
     // that check, as it ready only and must not change, unsetting it could
     // lead to recursions.
     if ($key = array_search($name, $this->getEntityType()->getKeys())) {
-      if (isset($this->entityKeys[$key]) && $key != 'bundle') {
-        unset($this->entityKeys[$key]);
+      if ($key != 'bundle') {
+        if (isset($this->entityKeys[$key])) {
+          unset($this->entityKeys[$key]);
+        }
+        elseif (isset($this->translatableEntityKeys[$key][$this->activeLangcode])) {
+          unset($this->translatableEntityKeys[$key][$this->activeLangcode]);
+        }
       }
     }
 
@@ -710,8 +744,6 @@ protected function initializeTranslation($langcode) {
     $translation->enforceIsNew = &$this->enforceIsNew;
     $translation->newRevision = &$this->newRevision;
     $translation->translationInitialize = FALSE;
-    // Reset language-dependent properties.
-    unset($translation->entityKeys['label']);
     $translation->typedData = NULL;
 
     return $translation;
@@ -1020,18 +1052,34 @@ public function referencedEntities() {
    *   The value of the entity key, NULL if not defined.
    */
   protected function getEntityKey($key) {
-    if (!isset($this->entityKeys[$key]) || !array_key_exists($key, $this->entityKeys)) {
-      if ($this->getEntityType()->hasKey($key)) {
-        $field_name = $this->getEntityType()->getKey($key);
-        $property = $this->getFieldDefinition($field_name)->getFieldStorageDefinition()->getMainPropertyName();
-        $this->entityKeys[$key] = $this->get($field_name)->$property;
+    // If the value is known already, return it.
+    if (isset($this->entityKeys[$key])) {
+      return $this->entityKeys[$key];
+    }
+    if (isset($this->translatableEntityKeys[$key][$this->activeLangcode])) {
+      return $this->translatableEntityKeys[$key][$this->activeLangcode];
+    }
+
+    // Otherwise fetch the value by creating a field object.
+    $value = NULL;
+    if ($this->getEntityType()->hasKey($key)) {
+      $field_name = $this->getEntityType()->getKey($key);
+      $definition = $this->getFieldDefinition($field_name);
+      $property = $definition->getFieldStorageDefinition()->getMainPropertyName();
+      $value = $this->get($field_name)->$property;
+
+      // Put it in the right array, depending on whether it is translatable.
+      if ($definition->isTranslatable()) {
+        $this->translatableEntityKeys[$key][$this->activeLangcode] = $value;
       }
       else {
-        $this->entityKeys[$key] = NULL;
+        $this->entityKeys[$key] = $value;
       }
-
     }
-    return $this->entityKeys[$key];
+    else {
+      $this->entityKeys[$key] = $value;
+    }
+    return $value;
   }
 
   /**
diff --git a/core/modules/node/src/Entity/Node.php b/core/modules/node/src/Entity/Node.php
index 2f57843bf4b9313c84881980db3688545b1a5f50..afa31e3c797b0fca32d8b98c1bb005b11e1dd2a9 100644
--- a/core/modules/node/src/Entity/Node.php
+++ b/core/modules/node/src/Entity/Node.php
@@ -53,7 +53,9 @@
  *     "bundle" = "type",
  *     "label" = "title",
  *     "langcode" = "langcode",
- *     "uuid" = "uuid"
+ *     "uuid" = "uuid",
+ *     "status" = "status",
+ *     "uid" = "uid",
  *   },
  *   bundle_entity_type = "node_type",
  *   field_ui_base_route = "entity.node_type.edit_form",
@@ -72,6 +74,13 @@ class Node extends ContentEntityBase implements NodeInterface {
 
   use EntityChangedTrait;
 
+  /**
+   * Whether the node is being previewed or not.
+   *
+   * @var true|null
+   */
+  public $in_preview = NULL;
+
   /**
    * {@inheritdoc}
    */
@@ -258,7 +267,7 @@ public function setSticky($sticky) {
    * {@inheritdoc}
    */
   public function isPublished() {
-    return (bool) $this->get('status')->value;
+    return (bool) $this->getEntityKey('status');
   }
 
   /**
@@ -280,7 +289,7 @@ public function getOwner() {
    * {@inheritdoc}
    */
   public function getOwnerId() {
-    return $this->get('uid')->target_id;
+    return $this->getEntityKey('uid');
   }
 
   /**
diff --git a/core/modules/node/src/NodeForm.php b/core/modules/node/src/NodeForm.php
index 33dec701f940d8c37716672448b492164d10d33b..c5846606831da4ba23fb730eba94476f51752874 100644
--- a/core/modules/node/src/NodeForm.php
+++ b/core/modules/node/src/NodeForm.php
@@ -7,7 +7,6 @@
 
 namespace Drupal\node;
 
-use Drupal\Component\Utility\Html;
 use Drupal\Core\Entity\ContentEntityForm;
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Form\FormStateInterface;
@@ -204,9 +203,32 @@ public function form(array $form, FormStateInterface $form_state) {
 
     $form['#attached']['library'][] = 'node/form';
 
+    $form['#entity_builders']['update_status'] = [$this, 'updateStatus'];
+
     return $form;
   }
 
+  /**
+   * Entity builder updating the node status with the submitted value.
+   *
+   * @param string $entity_type_id
+   *   The entity type identifier.
+   * @param \Drupal\node\NodeInterface $node
+   *   The node updated with the submitted values.
+   * @param array $form
+   *   The complete form array.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
+   *
+   * @see \Drupal\node\NodeForm::form()
+   */
+  function updateStatus($entity_type_id, NodeInterface $node, array $form, FormStateInterface $form_state) {
+    $element = $form_state->getTriggeringElement();
+    if (isset($element['#published_status'])) {
+      $node->setPublished($element['#published_status']);
+    }
+  }
+
   /**
    * {@inheritdoc}
    */
@@ -232,6 +254,8 @@ protected function actions(array $form, FormStateInterface $form_state) {
 
       // Add a "Publish" button.
       $element['publish'] = $element['submit'];
+      // If the "Publish" button is clicked, we want to update the status to "published".
+      $element['publish']['#published_status'] = TRUE;
       $element['publish']['#dropbutton'] = 'save';
       if ($node->isNew()) {
         $element['publish']['#value'] = t('Save and publish');
@@ -240,10 +264,11 @@ protected function actions(array $form, FormStateInterface $form_state) {
         $element['publish']['#value'] = $node->isPublished() ? t('Save and keep published') : t('Save and publish');
       }
       $element['publish']['#weight'] = 0;
-      array_unshift($element['publish']['#submit'], '::publish');
 
       // Add a "Unpublish" button.
       $element['unpublish'] = $element['submit'];
+      // If the "Unpublish" button is clicked, we want to update the status to "unpublished".
+      $element['unpublish']['#published_status'] = FALSE;
       $element['unpublish']['#dropbutton'] = 'save';
       if ($node->isNew()) {
         $element['unpublish']['#value'] = t('Save as unpublished');
@@ -252,7 +277,6 @@ protected function actions(array $form, FormStateInterface $form_state) {
         $element['unpublish']['#value'] = !$node->isPublished() ? t('Save and keep unpublished') : t('Save and unpublish');
       }
       $element['unpublish']['#weight'] = 10;
-      array_unshift($element['unpublish']['#submit'], '::unpublish');
 
       // If already published, the 'publish' button is primary.
       if ($node->isPublished()) {
@@ -327,34 +351,6 @@ public function preview(array $form, FormStateInterface $form_state) {
     ));
   }
 
-  /**
-   * Form submission handler for the 'publish' action.
-   *
-   * @param $form
-   *   An associative array containing the structure of the form.
-   * @param $form_state
-   *   The current state of the form.
-   */
-  public function publish(array $form, FormStateInterface $form_state) {
-    $node = $this->entity;
-    $node->setPublished(TRUE);
-    return $node;
-  }
-
-  /**
-   * Form submission handler for the 'unpublish' action.
-   *
-   * @param $form
-   *   An associative array containing the structure of the form.
-   * @param $form_state
-   *   The current state of the form.
-   */
-  public function unpublish(array $form, FormStateInterface $form_state) {
-    $node = $this->entity;
-    $node->setPublished(FALSE);
-    return $node;
-  }
-
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/node/src/NodeTranslationHandler.php b/core/modules/node/src/NodeTranslationHandler.php
index 3692c8b767ee60a13af5aa0ba3474f5ea6ce3862..41c6909535219432a6e1fdf2218d40639d2d825a 100644
--- a/core/modules/node/src/NodeTranslationHandler.php
+++ b/core/modules/node/src/NodeTranslationHandler.php
@@ -7,8 +7,8 @@
 
 namespace Drupal\node;
 
-use Drupal\Core\Entity\EntityInterface;
 use Drupal\content_translation\ContentTranslationHandler;
+use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Form\FormStateInterface;
 
 /**
@@ -76,9 +76,8 @@ protected function entityFormTitle(EntityInterface $entity) {
    */
   public function entityFormEntityBuild($entity_type, EntityInterface $entity, array $form, FormStateInterface $form_state) {
     if ($form_state->hasValue('content_translation')) {
-      $form_object = $form_state->getFormObject();
       $translation = &$form_state->getValue('content_translation');
-      $translation['status'] = $form_object->getEntity()->isPublished();
+      $translation['status'] = $entity->isPublished();
       // $form['content_translation']['name'] is the equivalent field
       // for translation author uid.
       $account = $entity->uid->entity;
diff --git a/core/modules/node/src/Tests/NodeTranslationUITest.php b/core/modules/node/src/Tests/NodeTranslationUITest.php
index 608ab43e406b8fb1d942980adc978ff01354f083..287920bf6937270f0c125c86d982e81dc5081419 100644
--- a/core/modules/node/src/Tests/NodeTranslationUITest.php
+++ b/core/modules/node/src/Tests/NodeTranslationUITest.php
@@ -12,6 +12,7 @@
 use Drupal\Core\Language\LanguageInterface;
 use Drupal\Core\Url;
 use Drupal\node\Entity\Node;
+use Drupal\language\Entity\ConfigurableLanguage;
 
 /**
  * Tests the Node Translation UI.
@@ -57,6 +58,42 @@ function testTranslationUI() {
     $this->doUninstallTest();
   }
 
+  /**
+   * Tests changing the published status on a node without fields.
+   */
+  function testPublishedStatusNoFields() {
+    // Test changing the published status of an article without fields.
+    $this->drupalLogin($this->administrator);
+    // Delete all fields.
+    $this->drupalGet('admin/structure/types/manage/article/fields');
+    $this->drupalPostForm('admin/structure/types/manage/article/fields/node.article.' . $this->fieldName . '/delete', array(), t('Delete'));
+    $this->drupalPostForm('admin/structure/types/manage/article/fields/node.article.field_tags/delete', array(), t('Delete'));
+    $this->drupalPostForm('admin/structure/types/manage/article/fields/node.article.field_image/delete', array(), t('Delete'));
+
+    // Add a node.
+    $default_langcode = $this->langcodes[0];
+    $values[$default_langcode] = array('title' => array(array('value' => $this->randomMachineName())));
+    $entity_id = $this->createEntity($values[$default_langcode], $default_langcode);
+    $entity = entity_load($this->entityTypeId, $entity_id, TRUE);
+
+    // Add a content translation.
+    $langcode = 'fr';
+    $language = ConfigurableLanguage::load($langcode);
+    $values[$langcode] = array('title' => array(array('value' => $this->randomMachineName())));
+
+    $add_url = Url::fromRoute('content_translation.translation_add_' . $entity->getEntityTypeId(), [
+      $entity->getEntityTypeId() => $entity->id(),
+      'source' => $default_langcode,
+      'target' => $langcode
+    ], array('language' => $language));
+    $this->drupalPostForm($add_url, $this->getEditValues($values, $langcode), t('Save and unpublish (this translation)'));
+
+    $entity = entity_load($this->entityTypeId, $this->entityId, TRUE);
+    $translation = $entity->getTranslation($langcode);
+    // Make sure we unpublished the node correctly.
+    $this->assertFalse($this->manager->getTranslationMetadata($translation)->isPublished(), 'The translation has been correctly unpublished.');
+  }
+
   /**
    * Overrides \Drupal\content_translation\Tests\ContentTranslationUITestBase::getTranslatorPermission().
    */
diff --git a/core/modules/system/src/Tests/Installer/InstallerTranslationTest.php b/core/modules/system/src/Tests/Installer/InstallerTranslationTest.php
index 7f3a66ffec1c7f2947189727b8d170aa2b7a1988..215f60ef2bf0ad745c6f6724188a3bc28844ff6c 100644
--- a/core/modules/system/src/Tests/Installer/InstallerTranslationTest.php
+++ b/core/modules/system/src/Tests/Installer/InstallerTranslationTest.php
@@ -57,6 +57,8 @@ public function testInstaller() {
     $this->assertText('German');
     $this->assertNoText('English');
 
+    // The current container still has the english as current language, rebuild.
+    $this->rebuildContainer();
     /** @var \Drupal\user\Entity\User $account */
     $account = User::load(0);
     $this->assertEqual($account->language()->getId(), 'en', 'Anonymous user is English.');