diff --git a/core/lib/Drupal/Core/Entity/EntityPublishedInterface.php b/core/lib/Drupal/Core/Entity/EntityPublishedInterface.php
new file mode 100644
index 0000000..77dcb2b
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/EntityPublishedInterface.php
@@ -0,0 +1,32 @@
+<?php
+
+namespace Drupal\Core\Entity;
+
+/**
+ * Provides an interface for access to an entity's published state.
+ */
+interface EntityPublishedInterface {
+
+  /**
+   * Returns whether or not the entity is published.
+   *
+   * @return bool
+   *   TRUE if the entity is published, FALSE otherwise.
+   */
+  public function isPublished();
+
+  /**
+   * Sets the entity as published.
+   *
+   * @return $this
+   */
+  public function publish();
+
+  /**
+   * Sets the entity as unpublished.
+   *
+   * @return $this
+   */
+   public function unpublish();
+
+}
diff --git a/core/lib/Drupal/Core/Entity/EntityPublishedTrait.php b/core/lib/Drupal/Core/Entity/EntityPublishedTrait.php
index 2145f4a..e295400 100644
--- a/core/lib/Drupal/Core/Entity/EntityPublishedTrait.php
+++ b/core/lib/Drupal/Core/Entity/EntityPublishedTrait.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\Core\Entity;
 
+use Drupal\Core\Entity\Exception\UnsupportedEntityTypeDefinitionException;
 use Drupal\Core\Field\BaseFieldDefinition;
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 
@@ -17,11 +18,21 @@
    *   The entity type to add the publishing status field to.
    *
    * @return \Drupal\Core\Field\BaseFieldDefinition[]
-   *   Array of base field definitions.
+   *   An array of base field definitions.
+   *
+   * @throws \Drupal\Core\Entity\Exception\UnsupportedEntityTypeDefinitionException
+   *   Thrown when the entity type does not implement EntityPublishedInterface
+   *   or if it does not have a "published" entity key.
    */
   public static function publishedBaseFieldDefinitions(EntityTypeInterface $entity_type) {
-    $key = $entity_type->hasKey('status') ? $entity_type->getKey('status') : 'status';
-    return [$key => BaseFieldDefinition::create('boolean')
+    if (!is_subclass_of($entity_type->getClass(), EntityPublishedInterface::class)) {
+      throw new UnsupportedEntityTypeDefinitionException('The entity type ' . $entity_type->id() . ' does not implement \Drupal\Core\Entity\EntityPublishedInterface.');
+    }
+    if (!$entity_type->hasKey('published')) {
+      throw new UnsupportedEntityTypeDefinitionException('The entity type ' . $entity_type->id() . ' does not have a "published" entity key.');
+    }
+
+    return [$entity_type->getKey('published') => BaseFieldDefinition::create('boolean')
       ->setLabel(new TranslatableMarkup('Publishing status'))
       ->setDescription(new TranslatableMarkup('A boolean indicating the published state.'))
       ->setRevisionable(TRUE)
@@ -30,31 +41,30 @@ public static function publishedBaseFieldDefinitions(EntityTypeInterface $entity
   }
 
   /**
-   * Returns the published status of the entity.
-   *
-   * @return bool
-   *   The published status of the entity.
+   * {@inheritdoc}
    */
   public function isPublished() {
-    $status = $this->getEntityKey('status');
-    return (bool) (isset($status) ? $status : $this->get('status')->value);
+    $key = $this->getEntityType()->getKey('published');
+    return (bool) $this->get($key)->value;
   }
 
   /**
-   * Sets the entity as published or not published.
-   *
-   * @param bool $published
-   *   A boolean value denoting the published status.
-   *
-   * @return \Drupal\Core\Entity\ContentEntityInterface $this
-   *   The Content Entity object.
+   * {@inheritdoc}
+   */
+  public function publish() {
+    $key = $this->getEntityType()->getKey('published');
+    $this->set($key, TRUE);
+
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
    */
-  public function setPublished($published) {
-    /** @var \Drupal\Core\Entity\ContentEntityTypeInterface $entity_type */
-    $key = $this->getEntityType()->getKey('status') ?: 'status';
-    // @todo: Replace values with constants from EntityPublishedInterface or
-    // similar when introduced. https://www.drupal.org/node/2811667
-    $this->set($key, $published ? 1 : 0);
+  public function unpublish() {
+    $key = $this->getEntityType()->getKey('published');
+    $this->set($key, FALSE);
+
     return $this;
   }
 
diff --git a/core/lib/Drupal/Core/Entity/Exception/UnsupportedEntityTypeDefinitionException.php b/core/lib/Drupal/Core/Entity/Exception/UnsupportedEntityTypeDefinitionException.php
new file mode 100644
index 0000000..079b422
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/Exception/UnsupportedEntityTypeDefinitionException.php
@@ -0,0 +1,8 @@
+<?php
+
+namespace Drupal\Core\Entity\Exception;
+
+/**
+ * Defines an exception thrown when an entity type definition is invalid.
+ */
+class UnsupportedEntityTypeDefinitionException extends \Exception { }
diff --git a/core/modules/comment/comment.install b/core/modules/comment/comment.install
index 38958aa..895c039 100644
--- a/core/modules/comment/comment.install
+++ b/core/modules/comment/comment.install
@@ -194,5 +194,17 @@ function comment_update_8300() {
 }
 
 /**
+ * Set the 'published' entity key.
+ */
+function comment_update_8301() {
+  $definition_update_manager = \Drupal::entityDefinitionUpdateManager();
+  $entity_type = $definition_update_manager->getEntityType('comment');
+  $keys = $entity_type->getKeys();
+  $keys['published'] = 'status';
+  $entity_type->set('entity_keys', $keys);
+  $definition_update_manager->updateEntityType($entity_type);
+}
+
+/**
  * @} End of "addtogroup updates-8.3.x".
  */
diff --git a/core/modules/comment/src/CommentInterface.php b/core/modules/comment/src/CommentInterface.php
index 28318ee..1f69e9a 100644
--- a/core/modules/comment/src/CommentInterface.php
+++ b/core/modules/comment/src/CommentInterface.php
@@ -3,13 +3,14 @@
 namespace Drupal\comment;
 
 use Drupal\Core\Entity\ContentEntityInterface;
+use Drupal\Core\Entity\EntityPublishedInterface;
 use Drupal\user\EntityOwnerInterface;
 use Drupal\Core\Entity\EntityChangedInterface;
 
 /**
  * Provides an interface defining a comment entity.
  */
-interface CommentInterface extends ContentEntityInterface, EntityChangedInterface, EntityOwnerInterface {
+interface CommentInterface extends ContentEntityInterface, EntityChangedInterface, EntityOwnerInterface, EntityPublishedInterface {
 
   /**
    * Comment is awaiting approval.
@@ -192,18 +193,13 @@ public function getCreatedTime();
   public function setCreatedTime($created);
 
   /**
-   * Checks if the comment is published.
-   *
-   * @return bool
-   *   TRUE if the comment is published.
-   */
-  public function isPublished();
-
-  /**
    * Returns the comment's status.
    *
    * @return int
    *   One of CommentInterface::PUBLISHED or CommentInterface::NOT_PUBLISHED
+   *
+   * @deprecated in Drupal 8.3.0, will be removed before Drupal 9.0.0. Use
+   *   \Drupal\Core\Entity\EntityPublishedInterface::isPublished() instead.
    */
   public function getStatus();
 
@@ -215,6 +211,10 @@ public function getStatus();
    *
    * @return \Drupal\comment\CommentInterface
    *   The class instance that this method is called on.
+   *
+   * @deprecated in Drupal 8.3.0, will be removed before Drupal 9.0.0. Use
+   *   \Drupal\Core\Entity\EntityPublishedInterface::publish() and
+   *   \Drupal\Core\Entity\EntityPublishedInterface::unpublish() instead.
    */
   public function setPublished($status);
 
diff --git a/core/modules/comment/src/Entity/Comment.php b/core/modules/comment/src/Entity/Comment.php
index a244163..5f96093 100644
--- a/core/modules/comment/src/Entity/Comment.php
+++ b/core/modules/comment/src/Entity/Comment.php
@@ -8,6 +8,7 @@
 use Drupal\comment\CommentInterface;
 use Drupal\Core\Entity\EntityChangedTrait;
 use Drupal\Core\Entity\EntityPublishedTrait;
+use Drupal\Core\Entity\EntityPublishedInterface;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Field\BaseFieldDefinition;
@@ -50,7 +51,8 @@
  *     "bundle" = "comment_type",
  *     "label" = "subject",
  *     "langcode" = "langcode",
- *     "uuid" = "uuid"
+ *     "uuid" = "uuid",
+ *     "published" = "status",
  *   },
  *   links = {
  *     "canonical" = "/comment/{comment}",
@@ -81,8 +83,12 @@ public function preSave(EntityStorageInterface $storage) {
     parent::preSave($storage);
 
     if (is_null($this->get('status')->value)) {
-      $published = \Drupal::currentUser()->hasPermission('skip comment approval') ? CommentInterface::PUBLISHED : CommentInterface::NOT_PUBLISHED;
-      $this->setPublished($published);
+      if (\Drupal::currentUser()->hasPermission('skip comment approval')) {
+        $this->publish();
+      }
+      else {
+        $this->unpublish();
+      }
     }
     if ($this->isNew()) {
       // Add the comment to database. This next section builds the thread field.
@@ -480,6 +486,19 @@ public function getStatus() {
   /**
    * {@inheritdoc}
    */
+  public function setPublished($status) {
+    if ($status) {
+      $this->publish();
+    }
+    else {
+      $this->unpublish();
+    }
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function getThread() {
     $thread = $this->get('thread');
     if (!empty($thread->value)) {
diff --git a/core/modules/comment/src/Tests/Update/CommentUpdateTest.php b/core/modules/comment/src/Tests/Update/CommentUpdateTest.php
index 61d187d..1bf3bdc 100644
--- a/core/modules/comment/src/Tests/Update/CommentUpdateTest.php
+++ b/core/modules/comment/src/Tests/Update/CommentUpdateTest.php
@@ -50,4 +50,22 @@ public function testCommentUpdate8101() {
     $this->assertIdentical($config->get('content.comment_forum.settings.view_mode'), 'default');
   }
 
+  /**
+   * Tests that the comment entity type has a 'published' entity key.
+   *
+   * @see comment_update_8301()
+   */
+  public function testPublishedEntityKey() {
+    // Check that the 'published' entity key does not exist prior to the update.
+    $entity_type = \Drupal::entityDefinitionUpdateManager()->getEntityType('comment');
+    $this->assertFalse($entity_type->getKey('published'));
+
+    // Run updates.
+    $this->runUpdates();
+
+    // Check that the entity key exists and it has the correct value.
+    $entity_type = \Drupal::entityDefinitionUpdateManager()->getEntityType('comment');
+    $this->assertEqual('status', $entity_type->getKey('published'));
+  }
+
 }
diff --git a/core/modules/node/node.install b/core/modules/node/node.install
index 720a7e0..2751b2c 100644
--- a/core/modules/node/node.install
+++ b/core/modules/node/node.install
@@ -222,6 +222,11 @@ function node_update_8003() {
 }
 
 /**
+ * @addtogroup updates-8.3.x
+ * @{
+ */
+
+/**
  * Change {node_access}.fallback from an int to a tinyint as it is a boolean.
  */
 function node_update_8300() {
@@ -234,3 +239,19 @@ function node_update_8300() {
     'size' => 'tiny',
   ]);
 }
+
+/**
+ * Set the 'published' entity key.
+ */
+function node_update_8301() {
+  $definition_update_manager = \Drupal::entityDefinitionUpdateManager();
+  $entity_type = $definition_update_manager->getEntityType('node');
+  $keys = $entity_type->getKeys();
+  $keys['published'] = 'status';
+  $entity_type->set('entity_keys', $keys);
+  $definition_update_manager->updateEntityType($entity_type);
+}
+
+/**
+ * @} End of "addtogroup updates-8.3.x".
+ */
diff --git a/core/modules/node/src/Entity/Node.php b/core/modules/node/src/Entity/Node.php
index d4e4715..e58d8b2 100644
--- a/core/modules/node/src/Entity/Node.php
+++ b/core/modules/node/src/Entity/Node.php
@@ -56,6 +56,7 @@
  *     "langcode" = "langcode",
  *     "uuid" = "uuid",
  *     "status" = "status",
+ *     "published" = "status",
  *     "uid" = "uid",
  *   },
  *   bundle_entity_type = "node_type",
@@ -248,6 +249,19 @@ public function setSticky($sticky) {
   /**
    * {@inheritdoc}
    */
+  public function setPublished($status) {
+    if ($status) {
+      $this->publish();
+    }
+    else {
+      $this->unpublish();
+    }
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function getOwner() {
     return $this->get('uid')->entity;
   }
diff --git a/core/modules/node/src/NodeInterface.php b/core/modules/node/src/NodeInterface.php
index 980dacd..0fba8fe 100644
--- a/core/modules/node/src/NodeInterface.php
+++ b/core/modules/node/src/NodeInterface.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\node;
 
+use Drupal\Core\Entity\EntityPublishedInterface;
 use Drupal\Core\Entity\RevisionLogInterface;
 use Drupal\user\EntityOwnerInterface;
 use Drupal\Core\Entity\EntityChangedInterface;
@@ -10,7 +11,7 @@
 /**
  * Provides an interface defining a node entity.
  */
-interface NodeInterface extends ContentEntityInterface, EntityChangedInterface, EntityOwnerInterface, RevisionLogInterface {
+interface NodeInterface extends ContentEntityInterface, EntityChangedInterface, EntityOwnerInterface, RevisionLogInterface, EntityPublishedInterface {
 
   /**
    * Gets the node type.
@@ -97,23 +98,17 @@ public function isSticky();
   public function setSticky($sticky);
 
   /**
-   * Returns the node published status indicator.
-   *
-   * Unpublished nodes are only visible to their authors and to administrators.
-   *
-   * @return bool
-   *   TRUE if the node is published.
-   */
-  public function isPublished();
-
-  /**
-   * Sets the published status of a node..
+   * Sets the published status of a node.
    *
    * @param bool $published
    *   TRUE to set this node to published, FALSE to set it to unpublished.
    *
    * @return \Drupal\node\NodeInterface
    *   The called node entity.
+   *
+   * @deprecated in Drupal 8.3.0, will be removed before Drupal 9.0.0. Use
+   *   \Drupal\Core\Entity\EntityPublishedInterface::publish() and
+   *   \Drupal\Core\Entity\EntityPublishedInterface::unpublish() instead.
    */
   public function setPublished($published);
 
diff --git a/core/modules/node/src/Tests/Update/NodeUpdateTest.php b/core/modules/node/src/Tests/Update/NodeUpdateTest.php
new file mode 100644
index 0000000..a8a1d28
--- /dev/null
+++ b/core/modules/node/src/Tests/Update/NodeUpdateTest.php
@@ -0,0 +1,41 @@
+<?php
+
+namespace Drupal\node\Tests\Update;
+
+use Drupal\system\Tests\Update\UpdatePathTestBase;
+
+/**
+ * Tests that node settings are properly updated during database updates.
+ *
+ * @group node
+ */
+class NodeUpdateTest extends UpdatePathTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setDatabaseDumpFiles() {
+    $this->databaseDumpFiles = [
+      __DIR__ . '/../../../../system/tests/fixtures/update/drupal-8.bare.standard.php.gz',
+    ];
+  }
+
+  /**
+   * Tests that the node entity type has a 'published' entity key.
+   *
+   * @see node_update_8301()
+   */
+  public function testPublishedEntityKey() {
+    // Check that the 'published' entity key does not exist prior to the update.
+    $entity_type = \Drupal::entityDefinitionUpdateManager()->getEntityType('node');
+    $this->assertFalse($entity_type->getKey('published'));
+
+    // Run updates.
+    $this->runUpdates();
+
+    // Check that the entity key exists and it has the correct value.
+    $entity_type = \Drupal::entityDefinitionUpdateManager()->getEntityType('node');
+    $this->assertEqual('status', $entity_type->getKey('published'));
+  }
+
+}
diff --git a/core/modules/rest/src/Tests/UpdateTest.php b/core/modules/rest/src/Tests/UpdateTest.php
index 287c2df..4fb84b0 100644
--- a/core/modules/rest/src/Tests/UpdateTest.php
+++ b/core/modules/rest/src/Tests/UpdateTest.php
@@ -311,7 +311,6 @@ public function testUpdateComment() {
     $this->pass('Test case 1: PATCH comment using JSON.');
     $comment->setSubject('Initial subject')->save();
     $read_only_fields = [
-      'status',
       'pid', // Extra compared to HAL+JSON.
       'entity_id',
       'uid',
