diff --git a/core/modules/node/lib/Drupal/node/NodeStorageController.php b/core/modules/node/lib/Drupal/node/NodeStorageController.php
index 693b828d9576b201d60b22ced8a0b918f1f44287..d105abf8e0e233471438567bc82b81d7caea6cf1 100644
--- a/core/modules/node/lib/Drupal/node/NodeStorageController.php
+++ b/core/modules/node/lib/Drupal/node/NodeStorageController.php
@@ -155,6 +155,13 @@ public function baseFieldDefinitions() {
       'label' => t('Title'),
       'description' => t('The title of this node, always treated as non-markup plain text.'),
       'type' => 'string_field',
+      'required' => TRUE,
+      'settings' => array(
+        'default_value' => '',
+      ),
+      'property_constraints' => array(
+        'value' => array('Length' => array('max' => 255)),
+      ),
     );
     $properties['uid'] = array(
       'label' => t('User ID'),
@@ -176,6 +183,9 @@ public function baseFieldDefinitions() {
       'label' => t('Changed'),
       'description' => t('The time that the node was last edited.'),
       'type' => 'integer_field',
+      'property_constraints' => array(
+        'value' => array('NodeChanged' => array()),
+      ),
     );
     $properties['comment'] = array(
       'label' => t('Comment'),
diff --git a/core/modules/node/lib/Drupal/node/Plugin/Validation/Constraint/NodeChangedConstraint.php b/core/modules/node/lib/Drupal/node/Plugin/Validation/Constraint/NodeChangedConstraint.php
new file mode 100644
index 0000000000000000000000000000000000000000..1ca461f9aa33ae49415551fc3db9c2f7eb472459
--- /dev/null
+++ b/core/modules/node/lib/Drupal/node/Plugin/Validation/Constraint/NodeChangedConstraint.php
@@ -0,0 +1,25 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\node\Plugin\Validation\Constraint\NodeChangedConstraint.
+ */
+
+namespace Drupal\node\Plugin\Validation\Constraint;
+
+use Drupal\Component\Annotation\Plugin;
+use Drupal\Core\Annotation\Translation;
+use Symfony\Component\Validator\Constraint;
+
+/**
+ * Validation constraint for the node changed timestamp.
+ *
+ * @Plugin(
+ *   id = "NodeChanged",
+ *   label = @Translation("Node changed", context = "Validation")
+ * )
+ */
+class NodeChangedConstraint extends Constraint {
+
+  public $message = 'The content has either been modified by another user, or you have already submitted modifications. As a result, your changes cannot be saved.';
+}
diff --git a/core/modules/node/lib/Drupal/node/Plugin/Validation/Constraint/NodeChangedConstraintValidator.php b/core/modules/node/lib/Drupal/node/Plugin/Validation/Constraint/NodeChangedConstraintValidator.php
new file mode 100644
index 0000000000000000000000000000000000000000..0479e3864072a92be6180bbbaedc386ca848f589
--- /dev/null
+++ b/core/modules/node/lib/Drupal/node/Plugin/Validation/Constraint/NodeChangedConstraintValidator.php
@@ -0,0 +1,33 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\node\Plugin\Validation\Constraint\NodeChangedConstraintValidator.
+ */
+
+namespace Drupal\node\Plugin\Validation\Constraint;
+
+use Symfony\Component\Validator\Constraint;
+use Symfony\Component\Validator\ConstraintValidator;
+
+/**
+ * Validates the NodeChanged constraint.
+ */
+class NodeChangedConstraintValidator extends ConstraintValidator {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function validate($value, Constraint $constraint) {
+    if (isset($value)) {
+      // We are on the field item level, so we need to go two levels up for the
+      // node object.
+      $node = $this->context->getMetadata()->getTypedData()->getParent()->getParent();
+      $id = $node->id();
+      $language = $node->language();
+      if ($id && (node_last_changed($id, $language->id) > $value)) {
+        $this->context->addViolation($constraint->message);
+      }
+    }
+  }
+}
diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeValidationTest.php b/core/modules/node/lib/Drupal/node/Tests/NodeValidationTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..dcba3e21391d67dada7b77c6e65034dedb236e92
--- /dev/null
+++ b/core/modules/node/lib/Drupal/node/Tests/NodeValidationTest.php
@@ -0,0 +1,77 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\node\Tests\NodeValidationTest.
+ */
+
+namespace Drupal\node\Tests;
+
+use Drupal\simpletest\DrupalUnitTestBase;
+
+/**
+ * Tests node validation constraints.
+ */
+class NodeValidationTest extends DrupalUnitTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('node', 'entity', 'field', 'text', 'field_sql_storage');
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Node Validation',
+      'description' => 'Tests the node validation constraints.',
+      'group' => 'Node',
+    );
+  }
+
+  /**
+   * Set the default field storage backend for fields created during tests.
+   */
+  public function setUp() {
+    parent::setUp();
+    $this->installSchema('node', 'node');
+    $this->installSchema('node', 'node_field_data');
+    $this->installSchema('node', 'node_field_revision');
+
+    // Create a node type for testing.
+    $type = entity_create('node_type', array('type' => 'page', 'name' => 'page'));
+    $type->save();
+  }
+
+  /**
+   * Tests the node validation constraints.
+   */
+  public function testValidation() {
+    $node = entity_create('node', array('type' => 'page', 'title' => 'test'));
+    $violations = $node->validate();
+    $this->assertEqual(count($violations), 0, 'No violations when validating a default node.');
+
+    $node->set('title', $this->randomString(256));
+    $violations = $node->validate();
+    $this->assertEqual(count($violations), 1, 'Violation found when title is too long.');
+    $this->assertEqual($violations[0]->getPropertyPath(), 'title.0.value');
+    $this->assertEqual($violations[0]->getMessage(), t('This value is too long. It should have %limit characters or less.', array('%limit' => 255)));
+
+    $node->set('title', NULL);
+    $violations = $node->validate();
+    $this->assertEqual(count($violations), 1, 'Violation found when title is not set.');
+    $this->assertEqual($violations[0]->getPropertyPath(), 'title');
+    $this->assertEqual($violations[0]->getMessage(), t('This value should not be null.'));
+
+    // Make the title valid again.
+    $node->set('title', $this->randomString());
+    // Save the node so that it gets an ID and a changed date.
+    $node->save();
+    // Set the changed date to something in the far past.
+    $node->set('changed', 433918800);
+    $violations = $node->validate();
+    $this->assertEqual(count($violations), 1, 'Violation found when changed date is before the last changed date.');
+    $this->assertEqual($violations[0]->getPropertyPath(), 'changed.0.value');
+    $this->assertEqual($violations[0]->getMessage(), t('The content has either been modified by another user, or you have already submitted modifications. As a result, your changes cannot be saved.'));
+  }
+}