diff --git a/core/modules/contact/config/install/contact.form.personal.yml b/core/modules/contact/config/install/contact.form.personal.yml
index c766fdd..f08682a 100644
--- a/core/modules/contact/config/install/contact.form.personal.yml
+++ b/core/modules/contact/config/install/contact.form.personal.yml
@@ -6,3 +6,5 @@ label: 'Personal contact form'
 recipients: {  }
 reply: ''
 weight: 0
+message: 'Your message has been sent.'
+redirect: ''
diff --git a/core/modules/contact/config/schema/contact.schema.yml b/core/modules/contact/config/schema/contact.schema.yml
index 5a62e9d..77cfc18 100644
--- a/core/modules/contact/config/schema/contact.schema.yml
+++ b/core/modules/contact/config/schema/contact.schema.yml
@@ -22,6 +22,12 @@ contact.form.*:
     weight:
       type: integer
       label: 'Weight'
+    message:
+      type: label
+      label: 'Message'
+    redirect:
+      type: path
+      label: 'Redirect Path'
 
 contact.settings:
   type: config_object
diff --git a/core/modules/contact/contact.post_update.php b/core/modules/contact/contact.post_update.php
new file mode 100644
index 0000000..908c7a6
--- /dev/null
+++ b/core/modules/contact/contact.post_update.php
@@ -0,0 +1,30 @@
+<?php
+
+/**
+ * @file
+ * Post update functions for Contact.
+ */
+
+use Drupal\contact\Entity\ContactForm;
+
+/**
+ * @addtogroup updates-8.0.x-to-8.1.x
+ * @{
+ */
+
+/**
+ * Initialize 'message' and 'redirect' field values to 'contact_form' entities.
+ */
+function contact_post_update_add_message_redirect_field_to_contact_form() {
+  /** @var \Drupal\contact\ContactFormInterface $contact */
+  foreach(ContactForm::loadMultiple() as $contact) {
+    $contact
+      ->setMessage('Your message has been sent.')
+      ->setRedirectPath('')
+      ->save();
+  }
+}
+
+/**
+ * @} End of "addtogroup updates-8.0.x-to-8.1.x".
+ */
diff --git a/core/modules/contact/src/ContactFormEditForm.php b/core/modules/contact/src/ContactFormEditForm.php
index 3b7dbe3..f931c8c 100644
--- a/core/modules/contact/src/ContactFormEditForm.php
+++ b/core/modules/contact/src/ContactFormEditForm.php
@@ -9,6 +9,8 @@
 use Drupal\Core\Form\ConfigFormBaseTrait;
 use Drupal\Core\Form\FormStateInterface;
 use Egulias\EmailValidator\EmailValidator;
+use Drupal\Core\Path\PathValidatorInterface;
+use Drupal\Core\Render\Element\PathElement;
 
 /**
  * Base form for contact form edit forms.
@@ -24,13 +26,21 @@ class ContactFormEditForm extends EntityForm implements ContainerInjectionInterf
   protected $emailValidator;
 
   /**
+   * The path validator.
+   *
+   * @var \Drupal\Core\Path\PathValidatorInterface
+   */
+  protected $pathValidator;
+
+  /**
    * Constructs a new ContactFormEditForm.
    *
    * @param \Egulias\EmailValidator\EmailValidator $email_validator
    *   The email validator.
    */
-  public function __construct(EmailValidator $email_validator) {
+  public function __construct(EmailValidator $email_validator, PathValidatorInterface $path_validator) {
    $this->emailValidator = $email_validator;
+   $this->pathValidator = $path_validator;
   }
 
   /**
@@ -38,7 +48,8 @@ public function __construct(EmailValidator $email_validator) {
    */
   public static function create(ContainerInterface $container) {
     return new static(
-      $container->get('email.validator')
+      $container->get('email.validator'),
+      $container->get('path.validator')
     );
   }
 
@@ -82,6 +93,19 @@ public function form(array $form, FormStateInterface $form_state) {
       '#description' => $this->t("Example: 'webmaster@example.com' or 'sales@example.com,support@example.com' . To specify multiple recipients, separate each email address with a comma."),
       '#required' => TRUE,
     );
+    $form['message'] = array(
+      '#type' => 'textarea',
+      '#title' => $this->t('Message'),
+      '#default_value' => $contact_form->getMessage(),
+      '#description' => $this->t('The message to display to the user after submission of this form. Leave blank for no message.'),
+    );
+    $form['redirect'] = array(
+      '#type' => 'path',
+      '#title' => $this->t('Redirect path'),
+      '#convert_path' => PathElement::CONVERT_NONE,
+      '#default_value' => $contact_form->getRedirectPath(),
+      '#description' => $this->t('Specify an alternative path by which this data can be accessed. For example, type "/about" when writing an about page. Use a relative path with a slash in front.'),
+    );
     $form['reply'] = array(
       '#type' => 'textarea',
       '#title' => $this->t('Auto-reply'),
@@ -119,6 +143,12 @@ public function validateForm(array &$form, FormStateInterface $form_state) {
       }
     }
     $form_state->setValue('recipients', $recipients);
+    $redirect_url = $form_state->getValue('redirect');
+    if ($redirect_url && $this->pathValidator->isValid($redirect_url)) {
+      if(substr($redirect_url, 0, 1) != '/') {
+        $form_state->setErrorByName('redirect', $this->t('The path should start with /.'));
+      }
+    }
   }
 
   /**
diff --git a/core/modules/contact/src/ContactFormInterface.php b/core/modules/contact/src/ContactFormInterface.php
index f4222fb..202d90b 100644
--- a/core/modules/contact/src/ContactFormInterface.php
+++ b/core/modules/contact/src/ContactFormInterface.php
@@ -10,6 +10,14 @@
 interface ContactFormInterface extends ConfigEntityInterface {
 
   /**
+   * Returns the message to be displayed to user.
+   *
+   * @return string
+   *   A user message.
+   */
+  public function getMessage();
+
+  /**
    * Returns list of recipient email addresses.
    *
    * @return array
@@ -18,10 +26,28 @@
   public function getRecipients();
 
   /**
+   * Returns the path for redirect.
+   *
+   * @return string
+   *   The redirect path.
+   */
+  public function getRedirectPath();
+
+  /**
+   * Returns the url object for redirect path.
+   *
+   * Empty redirect property results a url object of front page.
+   *
+   * @return \Drupal\core\Url
+   *   The redirect url object.
+   */
+  public function getRedirectUrl();
+
+  /**
    * Returns an auto-reply message to send to the message author.
    *
    * @return string
-   *  An auto-reply message
+   *  An auto-reply message.
    */
   public function getReply();
 
@@ -34,6 +60,16 @@ public function getReply();
   public function getWeight();
 
   /**
+   * Sets the message to be displayed to the user.
+   *
+   * @param string $message
+   *   The message to display after form is submitted.
+   *
+   * @return $this
+   */
+  public function setMessage($message);
+
+  /**
    * Sets list of recipient email addresses.
    *
    * @param array $recipients
@@ -44,6 +80,16 @@ public function getWeight();
   public function setRecipients($recipients);
 
   /**
+   * Sets the redirect path.
+   *
+   * @param string $redirect
+   *   The desired path.
+   *
+   * @return $this
+   */
+  public function setRedirectPath($redirect);
+
+  /**
    * Sets an auto-reply message to send to the message author.
    *
    * @param string $reply
diff --git a/core/modules/contact/src/Entity/ContactForm.php b/core/modules/contact/src/Entity/ContactForm.php
index 255d514..a868049 100644
--- a/core/modules/contact/src/Entity/ContactForm.php
+++ b/core/modules/contact/src/Entity/ContactForm.php
@@ -4,6 +4,7 @@
 
 use Drupal\Core\Config\Entity\ConfigEntityBundleBase;
 use Drupal\contact\ContactFormInterface;
+use Drupal\Core\Url;
 
 /**
  * Defines the contact form entity.
@@ -39,6 +40,8 @@
  *     "recipients",
  *     "reply",
  *     "weight",
+ *     "message",
+ *     "redirect",
  *   }
  * )
  */
@@ -59,6 +62,13 @@ class ContactForm extends ConfigEntityBundleBase implements ContactFormInterface
   protected $label;
 
   /**
+   * The message displayed to user.
+   *
+   * @var string
+   */
+  protected $message;
+
+  /**
    * List of recipient email addresses.
    *
    * @var array
@@ -66,6 +76,13 @@ class ContactForm extends ConfigEntityBundleBase implements ContactFormInterface
   protected $recipients = array();
 
   /**
+   * The path to redirect to.
+   *
+   * @var string
+   */
+  protected $redirect;
+
+  /**
    * An auto-reply message.
    *
    * @var string
@@ -82,6 +99,21 @@ class ContactForm extends ConfigEntityBundleBase implements ContactFormInterface
   /**
    * {@inheritdoc}
    */
+  public function getMessage() {
+    return $this->get('message');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setMessage($message) {
+    $this->set('message', $message);
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function getRecipients() {
     return $this->recipients;
   }
@@ -97,6 +129,34 @@ public function setRecipients($recipients) {
   /**
    * {@inheritdoc}
    */
+  public function getRedirectPath() {
+    return $this->redirect;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getRedirectUrl() {
+    if ($this->redirect) {
+      $url = Url::fromUserInput($this->redirect);
+    }
+    else {
+      $url = Url::fromRoute('<front>');
+    }
+    return $url;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setRedirectPath($redirect) {
+    $this->set('redirect', $redirect);
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function getReply() {
     return $this->reply;
   }
diff --git a/core/modules/contact/src/MessageForm.php b/core/modules/contact/src/MessageForm.php
index 15ddd72..668dd06 100644
--- a/core/modules/contact/src/MessageForm.php
+++ b/core/modules/contact/src/MessageForm.php
@@ -206,9 +206,12 @@ public function save(array $form, FormStateInterface $form_state) {
     $message = $this->entity;
     $user = $this->currentUser();
     $this->mailHandler->sendMailMessages($message, $user);
+    $contact_form = $message->getContactForm();
 
     $this->flood->register('contact', $this->config('contact.settings')->get('flood.interval'));
-    drupal_set_message($this->t('Your message has been sent.'));
+    if ($submission_message = $contact_form->getMessage()) {
+      drupal_set_message($submission_message);
+    }
 
     // To avoid false error messages caused by flood control, redirect away from
     // the contact form; either to the contacted user account or the front page.
@@ -216,7 +219,7 @@ public function save(array $form, FormStateInterface $form_state) {
       $form_state->setRedirectUrl($message->getPersonalRecipient()->urlInfo());
     }
     else {
-      $form_state->setRedirect('<front>');
+      $form_state->setRedirectUrl($contact_form->getRedirectUrl());
     }
     // Save the message. In core this is a no-op but should contrib wish to
     // implement message storage, this will make the task of swapping in a real
diff --git a/core/modules/contact/src/Tests/ContactSitewideTest.php b/core/modules/contact/src/Tests/ContactSitewideTest.php
index ce69388..f42c0ce 100644
--- a/core/modules/contact/src/Tests/ContactSitewideTest.php
+++ b/core/modules/contact/src/Tests/ContactSitewideTest.php
@@ -5,6 +5,7 @@
 use Drupal\Component\Utility\Unicode;
 use Drupal\contact\Entity\ContactForm;
 use Drupal\Core\Mail\MailFormatHelper;
+use Drupal\Core\Url;
 use Drupal\field_ui\Tests\FieldUiTestTrait;
 use Drupal\simpletest\WebTestBase;
 use Drupal\Core\Entity\EntityTypeInterface;
@@ -146,7 +147,7 @@ function testSiteWideContact() {
     $this->assertEscaped($recipients[0]);
 
     // Test update contact form.
-    $this->updateContactForm($id, $label = $this->randomMachineName(16), $recipients_str = implode(',', array($recipients[0], $recipients[1])), $reply = $this->randomMachineName(30), FALSE);
+    $this->updateContactForm($id, $label = $this->randomMachineName(16), $recipients_str = implode(',', array($recipients[0], $recipients[1])), $reply = $this->randomMachineName(30), FALSE, 'Your message has been sent.', '/user');
     $config = $this->config('contact.form.' . $id)->get();
     $this->assertEqual($config['label'], $label);
     $this->assertEqual($config['recipients'], array($recipients[0], $recipients[1]));
@@ -290,6 +291,46 @@ function testSiteWideContact() {
     $this->assertEqual($mail['subject'], t('[@label] @subject', array('@label' => $label, '@subject' => $edit['subject[0][value]'])));
     $this->assertTrue(strpos($mail['body'], $field_label));
     $this->assertTrue(strpos($mail['body'], $edit[$field_name . '[0][value]']));
+
+    // Test messages and redirect.
+    /** @var \Drupal\contact\ContactFormInterface $form */
+    $form = ContactForm::load($contact_form);
+    $form->setMessage('Thanks for your submission.');
+    $form->setRedirectPath('/user/' . $admin_user->id());
+    $form->save();
+    // Check that the field is displayed.
+    $this->drupalGet('contact/' . $contact_form);
+
+    // Submit the contact form and verify the content.
+    $edit = array(
+      'subject[0][value]' => $this->randomMachineName(),
+      'message[0][value]' => $this->randomMachineName(),
+      $field_name . '[0][value]' => $this->randomMachineName(),
+    );
+    $this->drupalPostForm(NULL, $edit, t('Send message'));
+    $this->assertText('Thanks for your submission.');
+    $this->assertUrl('user/' . $admin_user->id());
+
+    // Test Empty message.
+    /** @var \Drupal\contact\ContactFormInterface $form */
+    $form = ContactForm::load($contact_form);
+    $form->setMessage('');
+    $form->setRedirectPath('/user/' . $admin_user->id());
+    $form->save();
+    $this->drupalGet('admin/structure/contact/manage/' . $contact_form);
+    // Check that the field is displayed.
+    $this->drupalGet('contact/' . $contact_form);
+
+    // Submit the contact form and verify the content.
+    $edit = array(
+      'subject[0][value]' => $this->randomMachineName(),
+      'message[0][value]' => $this->randomMachineName(),
+      $field_name . '[0][value]' => $this->randomMachineName(),
+    );
+    $this->drupalPostForm(NULL, $edit, t('Send message'));
+    $result = $this->xpath('//div[@role=:role]', array(':role' => 'contentinfo'));
+    $this->assertEqual(count($result), 0, 'Messages not found.');
+    $this->assertUrl('user/' . $admin_user->id());
   }
 
   /**
@@ -351,13 +392,17 @@ function testAutoReply() {
    *   form.
    * @param bool $selected
    *   A Boolean indicating whether the form should be selected by default.
+   * @param string $message
+   *   The message that will be displayed to a user upon completing the contact
+   *   form.
    * @param array $third_party_settings
    *   Array of third party settings to be added to the posted form data.
    */
-  function addContactForm($id, $label, $recipients, $reply, $selected, $third_party_settings = []) {
+  function addContactForm($id, $label, $recipients, $reply, $selected, $message = 'Your message has been sent.', $third_party_settings = []) {
     $edit = array();
     $edit['label'] = $label;
     $edit['id'] = $id;
+    $edit['message'] = $message;
     $edit['recipients'] = $recipients;
     $edit['reply'] = $reply;
     $edit['selected'] = ($selected ? TRUE : FALSE);
@@ -379,13 +424,20 @@ function addContactForm($id, $label, $recipients, $reply, $selected, $third_part
    *   form.
    * @param bool $selected
    *   A Boolean indicating whether the form should be selected by default.
+   * @param string $message
+   *   The message that will be displayed to a user upon completing the contact
+   *   form.
+   * @param string $redirect
+   *   The path where user will be redirect after this form has been submitted..
    */
-  function updateContactForm($id, $label, $recipients, $reply, $selected) {
+  function updateContactForm($id, $label, $recipients, $reply, $selected, $message = 'Your message has been sent.', $redirect = '/') {
     $edit = array();
     $edit['label'] = $label;
     $edit['recipients'] = $recipients;
     $edit['reply'] = $reply;
     $edit['selected'] = ($selected ? TRUE : FALSE);
+    $edit['message'] = $message;
+    $edit['redirect'] = $redirect;
     $this->drupalPostForm("admin/structure/contact/manage/$id", $edit, t('Save'));
   }
 
diff --git a/core/modules/contact/src/Tests/ContactStorageTest.php b/core/modules/contact/src/Tests/ContactStorageTest.php
index 0a5dbb5..6805ee2 100644
--- a/core/modules/contact/src/Tests/ContactStorageTest.php
+++ b/core/modules/contact/src/Tests/ContactStorageTest.php
@@ -47,7 +47,7 @@ public function testContactStorage() {
     $this->drupalLogin($admin_user);
     // Create first valid contact form.
     $mail = 'simpletest@example.com';
-    $this->addContactForm($id = Unicode::strtolower($this->randomMachineName(16)), $label = $this->randomMachineName(16), implode(',', array($mail)), '', TRUE, [
+    $this->addContactForm($id = Unicode::strtolower($this->randomMachineName(16)), $label = $this->randomMachineName(16), implode(',', array($mail)), '', TRUE, 'Your message has been sent.', [
       'send_a_pony' => 1,
     ]);
     $this->assertRaw(t('Contact form %label has been added.', array('%label' => $label)));
diff --git a/core/modules/contact/src/Tests/Update/ContactUpdateTest.php b/core/modules/contact/src/Tests/Update/ContactUpdateTest.php
new file mode 100644
index 0000000..cbef8fe
--- /dev/null
+++ b/core/modules/contact/src/Tests/Update/ContactUpdateTest.php
@@ -0,0 +1,50 @@
+<?php
+
+namespace Drupal\contact\Tests\Update;
+
+use Drupal\contact\Entity\ContactForm;
+use Drupal\system\Tests\Update\UpdatePathTestBase;
+
+/**
+ * Tests contact update path.
+ *
+ * @group contact
+ */
+class ContactUpdateTest extends UpdatePathTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setDatabaseDumpFiles() {
+    $this->databaseDumpFiles = [
+      __DIR__ . '/../../../../system/tests/fixtures/update/drupal-8.bare.standard.php.gz',
+    ];
+  }
+
+  /**
+   * Tests contact_form updates.
+   *
+   * @see contact_post_update_add_message_redirect_field_to_contact_form()
+   */
+  public function testPostUpdateContactFormFields() {
+    // Check that contact_form does not have fields redirect and message.
+    $entities = ContactForm::loadMultiple();
+    foreach($entities as $contact) {
+      // Check whether 'message' and 'redirect' property does not exist for this entity.
+      $this->assertFalse(isset($contact->message), 'Message does not exist');
+      $this->assertFalse(isset($contact->redirect), 'Redirect does not exist');
+    }
+
+    // Run updates.
+    $this->runUpdates();
+
+    // Check that contact_form have fields 'redirect' and 'message'.
+    $entities = ContactForm::loadMultiple();
+    foreach($entities as $contact) {
+      // Check whether 'message' and 'redirect' property exist for this entity.
+      $this->assertFalse(isset($contact->message), 'Message property exists');
+      $this->assertFalse(isset($contact->redirect), 'Redirect property exists');
+    }
+  }
+
+}
diff --git a/core/modules/contact/tests/modules/contact_test/config/install/contact.form.feedback.yml b/core/modules/contact/tests/modules/contact_test/config/install/contact.form.feedback.yml
index 8fb7765..d6e048f 100644
--- a/core/modules/contact/tests/modules/contact_test/config/install/contact.form.feedback.yml
+++ b/core/modules/contact/tests/modules/contact_test/config/install/contact.form.feedback.yml
@@ -5,3 +5,5 @@ reply: ''
 weight: 0
 status: true
 langcode: en
+message: 'Your message has been sent.'
+redirect: ''
diff --git a/core/modules/file/file.module b/core/modules/file/file.module
index bbf3bff..96bc90e 100644
--- a/core/modules/file/file.module
+++ b/core/modules/file/file.module
@@ -1177,7 +1177,7 @@ function file_managed_file_save_upload($element, FormStateInterface $form_state)
 
   $destination = isset($element['#upload_location']) ? $element['#upload_location'] : NULL;
   if (isset($destination) && !file_prepare_directory($destination, FILE_CREATE_DIRECTORY)) {
-    \Drupal::logger('file')->notice('The upload directory %directory for the file field !name could not be created or is not accessible. A newly uploaded file could not be saved in this directory as a consequence, and the upload was canceled.', array('%directory' => $destination, '!name' => $element['#field_name']));
+    \Drupal::logger('file')->notice('The upload directory %directory for the file field %name could not be created or is not accessible. A newly uploaded file could not be saved in this directory as a consequence, and the upload was canceled.', array('%directory' => $destination, '%name' => $element['#field_name']));
     $form_state->setError($element, t('The file could not be uploaded.'));
     return FALSE;
   }
diff --git a/core/modules/rest/src/ModifiedResourceResponse.php b/core/modules/rest/src/ModifiedResourceResponse.php
new file mode 100644
index 0000000..8d88ef2
--- /dev/null
+++ b/core/modules/rest/src/ModifiedResourceResponse.php
@@ -0,0 +1,34 @@
+<?php
+
+namespace Drupal\rest;
+
+use Symfony\Component\HttpFoundation\Response;
+
+/**
+ * A response that does not contain cacheability metadata.
+ *
+ * Used when resources are modified by a request: responses to unsafe requests
+ * (POST/PATCH/DELETE) can never be cached.
+ *
+ * @see \Drupal\rest\ResourceResponse
+ */
+class ModifiedResourceResponse extends Response implements ResourceResponseInterface {
+
+  use ResourceResponseTrait;
+
+  /**
+   * Constructor for ModifiedResourceResponse objects.
+   *
+   * @param mixed $data
+   *   Response data that should be serialized.
+   * @param int $status
+   *   The response status code.
+   * @param array $headers
+   *   An array of response headers.
+   */
+  public function __construct($data = NULL, $status = 200, $headers = []) {
+    $this->responseData = $data;
+    parent::__construct('', $status, $headers);
+  }
+
+}
diff --git a/core/modules/rest/src/Plugin/rest/resource/EntityResource.php b/core/modules/rest/src/Plugin/rest/resource/EntityResource.php
index 6ec5f26..b4e78a4 100644
--- a/core/modules/rest/src/Plugin/rest/resource/EntityResource.php
+++ b/core/modules/rest/src/Plugin/rest/resource/EntityResource.php
@@ -6,6 +6,7 @@
 use Drupal\Core\Entity\EntityStorageException;
 use Drupal\rest\Plugin\ResourceBase;
 use Drupal\rest\ResourceResponse;
+use Drupal\rest\ModifiedResourceResponse;
 use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
 use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
 use Symfony\Component\HttpKernel\Exception\HttpException;
@@ -34,7 +35,7 @@ class EntityResource extends ResourceBase {
    * @param \Drupal\Core\Entity\EntityInterface $entity
    *   The entity object.
    *
-   * @return \Drupal\rest\ResourceResponse
+   * @return \Drupal\rest\ModifiedResourceResponse
    *   The response containing the entity with its accessible fields.
    *
    * @throws \Symfony\Component\HttpKernel\Exception\HttpException
@@ -108,11 +109,10 @@ public function post(EntityInterface $entity = NULL) {
       $this->logger->notice('Created entity %type with ID %id.', array('%type' => $entity->getEntityTypeId(), '%id' => $entity->id()));
 
       // 201 Created responses return the newly created entity in the response
-      // body.
+      // body. These responses are not cacheable, so we add no cacheability
+      // metadata here.
       $url = $entity->urlInfo('canonical', ['absolute' => TRUE])->toString(TRUE);
-      $response = new ResourceResponse($entity, 201, ['Location' => $url->getGeneratedUrl()]);
-      // Responses after creating an entity are not cacheable, so we add no
-      // cacheability metadata here.
+      $response = new ModifiedResourceResponse($entity, 201, ['Location' => $url->getGeneratedUrl()]);
       return $response;
     }
     catch (EntityStorageException $e) {
@@ -168,7 +168,7 @@ public function patch(EntityInterface $original_entity, EntityInterface $entity
       $this->logger->notice('Updated entity %type with ID %id.', array('%type' => $original_entity->getEntityTypeId(), '%id' => $original_entity->id()));
 
       // Update responses have an empty body.
-      return new ResourceResponse(NULL, 204);
+      return new ModifiedResourceResponse(NULL, 204);
     }
     catch (EntityStorageException $e) {
       throw new HttpException(500, 'Internal Server Error', $e);
@@ -195,7 +195,7 @@ public function delete(EntityInterface $entity) {
       $this->logger->notice('Deleted entity %type with ID %id.', array('%type' => $entity->getEntityTypeId(), '%id' => $entity->id()));
 
       // Delete responses have an empty body.
-      return new ResourceResponse(NULL, 204);
+      return new ModifiedResourceResponse(NULL, 204);
     }
     catch (EntityStorageException $e) {
       throw new HttpException(500, 'Internal Server Error', $e);
diff --git a/core/modules/rest/src/RequestHandler.php b/core/modules/rest/src/RequestHandler.php
index 8e0cd74..2aa3673 100644
--- a/core/modules/rest/src/RequestHandler.php
+++ b/core/modules/rest/src/RequestHandler.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\rest;
 
+use Drupal\Core\Cache\CacheableResponseInterface;
 use Drupal\Core\Render\RenderContext;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Symfony\Component\DependencyInjection\ContainerAwareInterface;
@@ -98,7 +99,7 @@ public function handle(RouteMatchInterface $route_match, Request $request) {
       return new Response($content, $e->getStatusCode(), $headers);
     }
 
-    return $response instanceof ResourceResponse ?
+    return $response instanceof ResourceResponseInterface ?
       $this->renderResponse($request, $response, $serializer, $format) :
       $response;
   }
@@ -124,7 +125,7 @@ public function csrfToken() {
    *
    * @param \Symfony\Component\HttpFoundation\Request $request
    *   The request object.
-   * @param \Drupal\rest\ResourceResponse $response
+   * @param \Drupal\rest\ResourceResponseInterface $response
    *   The response from the REST resource.
    * @param \Symfony\Component\Serializer\SerializerInterface $serializer
    *   The serializer to use.
@@ -137,22 +138,29 @@ public function csrfToken() {
    * @todo Add test coverage for language negotiation contexts in
    *   https://www.drupal.org/node/2135829.
    */
-  protected function renderResponse(Request $request, ResourceResponse $response, SerializerInterface $serializer, $format) {
+  protected function renderResponse(Request $request, ResourceResponseInterface $response, SerializerInterface $serializer, $format) {
     $data = $response->getResponseData();
-    $context = new RenderContext();
-    $output = $this->container->get('renderer')
-      ->executeInRenderContext($context, function () use ($serializer, $data, $format) {
-        return $serializer->serialize($data, $format);
-      });
-    $response->setContent($output);
-    if (!$context->isEmpty()) {
-      $response->addCacheableDependency($context->pop());
-    }
 
+    if ($response instanceof CacheableResponseInterface) {
+      $context = new RenderContext();
+      $output = $this->container->get('renderer')
+        ->executeInRenderContext($context, function () use ($serializer, $data, $format) {
+          return $serializer->serialize($data, $format);
+        });
+
+      if (!$context->isEmpty()) {
+        $response->addCacheableDependency($context->pop());
+      }
+
+      // Add rest settings config's cache tags.
+      $response->addCacheableDependency($this->container->get('config.factory')
+        ->get('rest.settings'));
+    }
+    else {
+      $output = $serializer->serialize($data, $format);
+    }
+    $response->setContent($output);
     $response->headers->set('Content-Type', $request->getMimeType($format));
-    // Add rest settings config's cache tags.
-    $response->addCacheableDependency($this->container->get('config.factory')
-      ->get('rest.settings'));
 
     return $response;
   }
diff --git a/core/modules/rest/src/ResourceResponse.php b/core/modules/rest/src/ResourceResponse.php
index 20a7e78..d4279a4 100644
--- a/core/modules/rest/src/ResourceResponse.php
+++ b/core/modules/rest/src/ResourceResponse.php
@@ -13,17 +13,13 @@
  * our response data. $content implies that the provided data must either be a
  * string or an object with a __toString() method, which is not a requirement
  * for data used here.
+ *
+ * @see \Drupal\rest\ModifiedResourceResponse
  */
-class ResourceResponse extends Response implements CacheableResponseInterface {
+class ResourceResponse extends Response implements CacheableResponseInterface, ResourceResponseInterface {
 
   use CacheableResponseTrait;
-
-  /**
-   * Response data that should be serialized.
-   *
-   * @var mixed
-   */
-  protected $responseData;
+  use ResourceResponseTrait;
 
   /**
    * Constructor for ResourceResponse objects.
@@ -40,14 +36,4 @@ public function __construct($data = NULL, $status = 200, $headers = array()) {
     parent::__construct('', $status, $headers);
   }
 
-  /**
-   * Returns response data that should be serialized.
-   *
-   * @return mixed
-   *   Response data that should be serialized.
-   */
-  public function getResponseData() {
-    return $this->responseData;
-  }
-
 }
diff --git a/core/modules/rest/src/ResourceResponseInterface.php b/core/modules/rest/src/ResourceResponseInterface.php
new file mode 100644
index 0000000..e52cf51
--- /dev/null
+++ b/core/modules/rest/src/ResourceResponseInterface.php
@@ -0,0 +1,18 @@
+<?php
+
+namespace Drupal\rest;
+
+/**
+ * Defines a common interface for resource responses.
+ */
+interface ResourceResponseInterface {
+
+  /**
+   * Returns response data that should be serialized.
+   *
+   * @return mixed
+   *   Response data that should be serialized.
+   */
+  public function getResponseData();
+
+}
diff --git a/core/modules/rest/src/ResourceResponseTrait.php b/core/modules/rest/src/ResourceResponseTrait.php
new file mode 100644
index 0000000..d16bc19
--- /dev/null
+++ b/core/modules/rest/src/ResourceResponseTrait.php
@@ -0,0 +1,25 @@
+<?php
+
+namespace Drupal\rest;
+
+
+trait ResourceResponseTrait {
+
+  /**
+   * Response data that should be serialized.
+   *
+   * @var mixed
+   */
+  protected $responseData;
+
+  /**
+   * Returns response data that should be serialized.
+   *
+   * @return mixed
+   *   Response data that should be serialized.
+   */
+  public function getResponseData() {
+    return $this->responseData;
+  }
+
+}
diff --git a/core/modules/rest/src/Tests/PageCacheTest.php b/core/modules/rest/src/Tests/PageCacheTest.php
index 1958fdc..0ce66da 100644
--- a/core/modules/rest/src/Tests/PageCacheTest.php
+++ b/core/modules/rest/src/Tests/PageCacheTest.php
@@ -2,6 +2,9 @@
 
 namespace Drupal\rest\Tests;
 
+use Drupal\Core\Url;
+use Drupal\system\Tests\Cache\AssertPageCacheContextsAndTagsTrait;
+
 /**
  * Tests page caching for REST GET requests.
  *
@@ -9,6 +12,8 @@
  */
 class PageCacheTest extends RESTTestBase {
 
+  use AssertPageCacheContextsAndTagsTrait;
+
   /**
    * Modules to install.
    *
@@ -17,21 +22,58 @@ class PageCacheTest extends RESTTestBase {
   public static $modules = array('hal', 'rest', 'entity_test');
 
   /**
+   * The 'serializer' service.
+   *
+   * @var \Symfony\Component\Serializer\Serializer
+   */
+  protected $serializer;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+    // Get the 'serializer' service.
+    $this->serializer = $this->container->get('serializer');
+  }
+
+  /**
    * Tests that configuration changes also clear the page cache.
    */
   public function testConfigChangePageCache() {
-    $this->enableService('entity:entity_test', 'GET');
     // Allow anonymous users to issue GET requests.
-    $permissions = $this->entityPermissions('entity_test', 'view');
-    $permissions[] = 'restful get entity:entity_test';
-    user_role_grant_permissions('anonymous', $permissions);
+    user_role_grant_permissions('anonymous', ['view test entity', 'restful get entity:entity_test']);
+
+    $this->enableService('entity:entity_test', 'POST');
+    $permissions = [
+      'administer entity_test content',
+      'restful post entity:entity_test',
+      'restful get entity:entity_test',
+      'restful patch entity:entity_test',
+      'restful delete entity:entity_test',
+    ];
+    $account = $this->drupalCreateUser($permissions);
 
-    // Create an entity programmatically.
+    // Create an entity and test that the response from a post request is not
+    // cacheable.
     $entity = $this->entityCreate('entity_test');
     $entity->set('field_test_text', 'custom cache tag value');
-    $entity->save();
+    $serialized = $this->serializer->serialize($entity, $this->defaultFormat);
+    // Log in for creating the entity.
+    $this->drupalLogin($account);
+    $this->httpRequest('entity/entity_test', 'POST', $serialized, $this->defaultMimeType);
+    $this->assertResponse(201);
+
+    if ($this->getCacheHeaderValues('x-drupal-cache')) {
+      $this->fail('Post request is cached.');
+    }
+    $this->drupalLogout();
+
+    $url = Url::fromUri('internal:/entity_test/1?_format=' . $this->defaultFormat);
+
     // Read it over the REST API.
-    $this->httpRequest($entity->urlInfo()->setRouteParameter('_format', $this->defaultFormat), 'GET', NULL, $this->defaultMimeType);
+    $this->enableService('entity:entity_test', 'GET');
+    $this->httpRequest($url, 'GET', NULL, $this->defaultMimeType);
     $this->assertResponse(200, 'HTTP response code is correct.');
     $this->assertHeader('x-drupal-cache', 'MISS');
     $this->assertCacheTag('config:rest.settings');
@@ -39,7 +81,7 @@ public function testConfigChangePageCache() {
     $this->assertCacheTag('entity_test_access:field_test_text');
 
     // Read it again, should be page-cached now.
-    $this->httpRequest($entity->urlInfo()->setRouteParameter('_format', $this->defaultFormat), 'GET', NULL, $this->defaultMimeType);
+    $this->httpRequest($url, 'GET', NULL, $this->defaultMimeType);
     $this->assertResponse(200, 'HTTP response code is correct.');
     $this->assertHeader('x-drupal-cache', 'HIT');
     $this->assertCacheTag('config:rest.settings');
@@ -49,12 +91,48 @@ public function testConfigChangePageCache() {
     // Trigger a config save which should clear the page cache, so we should get
     // a cache miss now for the same request.
     $this->config('rest.settings')->save();
-    $this->httpRequest($entity->urlInfo()->setRouteParameter('_format', $this->defaultFormat), 'GET', NULL, $this->defaultMimeType);
+    $this->httpRequest($url, 'GET', NULL, $this->defaultMimeType);
     $this->assertResponse(200, 'HTTP response code is correct.');
     $this->assertHeader('x-drupal-cache', 'MISS');
     $this->assertCacheTag('config:rest.settings');
     $this->assertCacheTag('entity_test:1');
     $this->assertCacheTag('entity_test_access:field_test_text');
+
+    // Log in for deleting / updating entity.
+    $this->drupalLogin($account);
+
+    // Test that updating an entity is not cacheable.
+    $this->enableService('entity:entity_test', 'PATCH');
+
+    // Create a second stub entity for overwriting a field.
+    $patch_values['field_test_text'] = [0 => [
+      'value' => 'patched value',
+      'format' => 'plain_text',
+    ]];
+    $patch_entity = $this->container->get('entity_type.manager')
+      ->getStorage('entity_test')
+      ->create($patch_values);
+    // We don't want to overwrite the UUID.
+    $patch_entity->set('uuid', NULL);
+    $serialized = $this->container->get('serializer')
+      ->serialize($patch_entity, $this->defaultFormat);
+
+    // Update the entity over the REST API.
+    $this->httpRequest($url, 'PATCH', $serialized, $this->defaultMimeType);
+    $this->assertResponse(204);
+
+    if ($this->getCacheHeaderValues('x-drupal-cache')) {
+      $this->fail('Patch request is cached.');
+    }
+
+    // Test that the response from a delete request is not cacheable.
+    $this->enableService('entity:entity_test', 'DELETE');
+    $this->httpRequest($url, 'DELETE');
+    $this->assertResponse(204);
+
+    if ($this->getCacheHeaderValues('x-drupal-cache')) {
+      $this->fail('Patch request is cached.');
+    }
   }
 
 }
diff --git a/core/profiles/standard/config/install/contact.form.feedback.yml b/core/profiles/standard/config/install/contact.form.feedback.yml
index 47f0e90..e222ecd 100644
--- a/core/profiles/standard/config/install/contact.form.feedback.yml
+++ b/core/profiles/standard/config/install/contact.form.feedback.yml
@@ -7,3 +7,5 @@ recipients:
   - admin@example.com
 reply: ''
 weight: 0
+message: 'Your message has been sent.'
+redirect: ''
