diff --git a/core/lib/Drupal/Core/Image/Image.php b/core/lib/Drupal/Core/Image/Image.php
index 42cdc92..585a1e6 100644
--- a/core/lib/Drupal/Core/Image/Image.php
+++ b/core/lib/Drupal/Core/Image/Image.php
@@ -188,8 +188,8 @@ public function rotate($degrees, $background = NULL) {
   /**
    * {@inheritdoc}
    */
-  public function scaleAndCrop($width, $height) {
-    return $this->apply('scale_and_crop', array('width' => $width, 'height' => $height));
+  public function scaleAndCrop($width, $height, $upscale = FALSE) {
+    return $this->apply('scale_and_crop', ['width' => $width, 'height' => $height, 'upscale' => $upscale]);
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Image/ImageInterface.php b/core/lib/Drupal/Core/Image/ImageInterface.php
index 9e112c6..ab8cad8 100644
--- a/core/lib/Drupal/Core/Image/ImageInterface.php
+++ b/core/lib/Drupal/Core/Image/ImageInterface.php
@@ -140,10 +140,11 @@ public function createNew($width, $height, $extension = 'png', $transparent_colo
    *   be based only on the height value.
    * @param int|null $height
    *   (optional) The target height, in pixels. If this value is null then the
-   *   scaling will be based only on the width value.
+   *   scaling will be based only on the width value. Defaults to NULL.
    * @param bool $upscale
    *   (optional) Boolean indicating that files smaller than the dimensions will
    *   be scaled up. This generally results in a low quality image.
+   *   Defaults to FALSE.
    *
    * @return bool
    *   TRUE on success, FALSE on failure.
@@ -163,11 +164,15 @@ public function scale($width, $height = NULL, $upscale = FALSE);
    *   The target width, in pixels.
    * @param int $height
    *   The target height, in pixels.
+   * @param bool $upscale
+   *   (optional) Boolean indicating that files smaller than the dimensions will
+   *   be scaled up. This generally results in a low quality image.
+   *   Defaults to FALSE.
    *
    * @return bool
    *   TRUE on success, FALSE on failure.
    */
-  public function scaleAndCrop($width, $height);
+  public function scaleAndCrop($width, $height, $upscale = FALSE);
 
   /**
    * Instructs the toolkit to save the image in the format specified by the
diff --git a/core/modules/image/config/schema/image.schema.yml b/core/modules/image/config/schema/image.schema.yml
index 0006ad7..0abbb67 100644
--- a/core/modules/image/config/schema/image.schema.yml
+++ b/core/modules/image/config/schema/image.schema.yml
@@ -76,6 +76,10 @@ image.effect.image_desaturate:
 image.effect.image_scale_and_crop:
   type: image_size
   label: 'Image scale and crop'
+  mapping:
+    upscale:
+      type: boolean
+      label: 'Upscale'
 
 image.settings:
   type: config_object
diff --git a/core/modules/image/image.module b/core/modules/image/image.module
index 7f8314a..b9c29e8 100644
--- a/core/modules/image/image.module
+++ b/core/modules/image/image.module
@@ -142,6 +142,9 @@ function image_theme() {
     'image_scale_summary' => array(
       'variables' => array('data' => NULL, 'effect' => array()),
     ),
+    'image_scale_and_crop_summary' => array(
+      'variables' => array('data' => NULL, 'effect' => array()),
+    ),
     'image_crop_summary' => array(
       'variables' => array('data' => NULL, 'effect' => array()),
     ),
diff --git a/core/modules/image/image.post_update.php b/core/modules/image/image.post_update.php
index 04d8c4b..2355b4f 100644
--- a/core/modules/image/image.post_update.php
+++ b/core/modules/image/image.post_update.php
@@ -7,6 +7,7 @@
 
 use Drupal\Core\Entity\Entity\EntityViewDisplay;
 use Drupal\Core\Entity\Entity\EntityFormDisplay;
+use Drupal\image\Entity\ImageStyle;
 
 /**
  * Saves the image style dependencies into form and view display entities.
@@ -20,3 +21,27 @@ function image_post_update_image_style_dependencies() {
     $display->save();
   }
 }
+
+/**
+ * @addtogroup updates-8.3.0
+ * @{
+ */
+
+/**
+ * Add 'upscale' parameter to 'Scale and crop' effects.
+ */
+function image_post_update_scale_and_crop_effect_upscale() {
+  foreach (ImageStyle::loadMultiple() as $image_style) {
+    foreach ($image_style->getEffects() as $effect) {
+      if ($effect->getPluginId() === 'image_scale_and_crop') {
+        $image_style->save();
+        break;
+
+      }
+    }
+  }
+}
+
+/**
+ * @} End of "addtogroup updates-8.3.0".
+ */
diff --git a/core/modules/image/src/Plugin/ImageEffect/ScaleAndCropImageEffect.php b/core/modules/image/src/Plugin/ImageEffect/ScaleAndCropImageEffect.php
index f2ab323..56dcf70 100644
--- a/core/modules/image/src/Plugin/ImageEffect/ScaleAndCropImageEffect.php
+++ b/core/modules/image/src/Plugin/ImageEffect/ScaleAndCropImageEffect.php
@@ -2,6 +2,8 @@
 
 namespace Drupal\image\Plugin\ImageEffect;
 
+use Drupal\Component\Utility\Image;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Image\ImageInterface;
 
 /**
@@ -19,11 +21,84 @@ class ScaleAndCropImageEffect extends ResizeImageEffect {
    * {@inheritdoc}
    */
   public function applyEffect(ImageInterface $image) {
-    if (!$image->scaleAndCrop($this->configuration['width'], $this->configuration['height'])) {
-      $this->logger->error('Image scale and crop failed using the %toolkit toolkit on %path (%mimetype, %dimensions)', array('%toolkit' => $image->getToolkitId(), '%path' => $image->getSource(), '%mimetype' => $image->getMimeType(), '%dimensions' => $image->getWidth() . 'x' . $image->getHeight()));
+    if (!$image->scaleAndCrop($this->configuration['width'], $this->configuration['height'], $this->configuration['upscale'])) {
+      $this->logger->error('Image scale and crop failed using the %toolkit toolkit on %path (%mimetype, %dimensions)', [
+        '%toolkit' => $image->getToolkitId(),
+        '%path' => $image->getSource(),
+        '%mimetype' => $image->getMimeType(),
+        '%dimensions' => $image->getWidth() . 'x' . $image->getHeight(),
+      ]);
       return FALSE;
     }
     return TRUE;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function transformDimensions(array &$dimensions, $uri) {
+    if (isset($dimensions['width'], $dimensions['height'])) {
+      $is_scaled = Image::scaleDimensions($dimensions, $this->configuration['width'], $this->configuration['height'], $this->configuration['upscale']);
+
+      // If image is not scaled save the original dimensions.
+      if (!$is_scaled) {
+        return;
+      }
+    }
+    $dimensions['width'] = $this->configuration['width'];
+    $dimensions['height'] = $this->configuration['height'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getSummary() {
+    return [
+      '#theme' => 'image_scale_and_crop_summary',
+    ] + parent::getSummary();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function defaultConfiguration() {
+    $configuration = parent::defaultConfiguration();
+    $configuration['upscale'] = FALSE;
+    return $configuration;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
+    $form = parent::buildConfigurationForm($form, $form_state);
+    $form['width']['#required'] = FALSE;
+    $form['height']['#required'] = FALSE;
+    $form['upscale'] = [
+      '#type' => 'checkbox',
+      '#default_value' => $this->configuration['upscale'],
+      '#title' => $this->t('Allow Upscaling'),
+      '#description' => $this->t('Let scale make images larger than their original size'),
+    ];
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
+    parent::validateConfigurationForm($form, $form_state);
+    if ($form_state->isValueEmpty('width') && $form_state->isValueEmpty('height')) {
+      $form_state->setErrorByName('data', $this->t('Width and height can not both be blank.'));
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
+    parent::submitConfigurationForm($form, $form_state);
+    $this->configuration['upscale'] = $form_state->getValue('upscale');
+  }
+
 }
diff --git a/core/modules/image/src/Tests/ImageAdminStylesTest.php b/core/modules/image/src/Tests/ImageAdminStylesTest.php
index 4b7ff43..f97f371 100644
--- a/core/modules/image/src/Tests/ImageAdminStylesTest.php
+++ b/core/modules/image/src/Tests/ImageAdminStylesTest.php
@@ -80,6 +80,7 @@ function testStyle() {
       'image_scale_and_crop' => array(
         'width' => 120,
         'height' => 121,
+        'upscale' => 1,
       ),
       'image_crop' => array(
         'width' => 130,
diff --git a/core/modules/image/src/Tests/ImageEffectsTest.php b/core/modules/image/src/Tests/ImageEffectsTest.php
index 895457f..298f134 100644
--- a/core/modules/image/src/Tests/ImageEffectsTest.php
+++ b/core/modules/image/src/Tests/ImageEffectsTest.php
@@ -51,10 +51,10 @@ function testResizeEffect() {
    * Test the image_scale_effect() function.
    */
   function testScaleEffect() {
-    // @todo: need to test upscaling.
     $this->assertImageEffect('image_scale', array(
       'width' => 10,
       'height' => 10,
+      'upscale' => 1,
     ));
     $this->assertToolkitOperationsCalled(array('scale'));
 
@@ -62,6 +62,7 @@ function testScaleEffect() {
     $calls = $this->imageTestGetAllCalls();
     $this->assertEqual($calls['scale'][0][0], 10, 'Width was passed correctly');
     $this->assertEqual($calls['scale'][0][1], 10, 'Height was based off aspect ratio and passed correctly');
+    $this->assertTrue($calls['scale'][0][2], 'Upscale was passed correctly');
   }
 
   /**
@@ -106,6 +107,7 @@ function testScaleAndCropEffect() {
     $this->assertImageEffect('image_scale_and_crop', array(
       'width' => 5,
       'height' => 10,
+      'upscale' => 1,
     ));
     $this->assertToolkitOperationsCalled(array('scale_and_crop'));
 
@@ -113,6 +115,7 @@ function testScaleAndCropEffect() {
     $calls = $this->imageTestGetAllCalls();
     $this->assertEqual($calls['scale_and_crop'][0][0], 5, 'Width was computed and passed correctly');
     $this->assertEqual($calls['scale_and_crop'][0][1], 10, 'Height was computed and passed correctly');
+    $this->assertTrue($calls['scale_and_crop'][0][2], 'Upscale was passed correctly');
   }
 
   /**
diff --git a/core/modules/image/src/Tests/Update/ScaleAndCropUpscaleUpdateTest.php b/core/modules/image/src/Tests/Update/ScaleAndCropUpscaleUpdateTest.php
new file mode 100644
index 0000000..20ab890
--- /dev/null
+++ b/core/modules/image/src/Tests/Update/ScaleAndCropUpscaleUpdateTest.php
@@ -0,0 +1,42 @@
+<?php
+
+namespace Drupal\image\Tests\Update;
+
+use Drupal\system\Tests\Update\UpdatePathTestBase;
+
+/**
+ * Tests the upgrade path for 'Scale and crop' effect 'upscale' parameter.
+ *
+ * @see image_post_update_scale_and_crop_effect_upscale()
+ *
+ * @group image
+ */
+class ScaleAndCropUpscaleUpdateTest extends UpdatePathTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setDatabaseDumpFiles() {
+    $this->databaseDumpFiles = [
+      __DIR__ . '/../../../../system/tests/fixtures/update/drupal-8.bare.standard.php.gz',
+      __DIR__ . '/../../../tests/fixtures/update/test_scale_and_crop_upscale.php',
+    ];
+  }
+
+  /**
+   * Tests that 'upscale' parameter is updated properly.
+   */
+  public function testImagePostUpdateScaleAndCropEffectUpscale() {
+    // Test that Scale and crop effect does not have 'upscale' parameter set.
+    $effect_data = $this->config('image.style.test_scale_and_crop_upscale')->get('effects.637b75a0-a80a-4bcc-8300-66994a27871d.data');
+    $this->assertFalse(array_key_exists('upscale', $effect_data));
+
+    $this->runUpdates();
+
+    // Test that Scale and crop effect has 'upscale' parameter set.
+    $effect_data = $this->config('image.style.test_scale_and_crop_upscale')->get('effects.637b75a0-a80a-4bcc-8300-66994a27871d.data');
+    $this->assertTrue(array_key_exists('upscale', $effect_data));
+    $this->assertFalse($effect_data['upscale']);
+  }
+
+}
diff --git a/core/modules/image/templates/image-scale-and-crop-summary.html.twig b/core/modules/image/templates/image-scale-and-crop-summary.html.twig
new file mode 100644
index 0000000..50b4406
--- /dev/null
+++ b/core/modules/image/templates/image-scale-and-crop-summary.html.twig
@@ -0,0 +1,37 @@
+{#
+/**
+ * @file
+ * Default theme implementation for a summary of an image scale and crop effect.
+ *
+ * Available variables:
+ * - data: The current configuration for this resize effect, including:
+ *   - width: The width of the resized image.
+ *   - height: The height of the resized image.
+ *   - upscale: If images larger than their original size can scale.
+ * - effect: The effect information, including:
+ *   - id: The effect identifier.
+ *   - label: The effect name.
+ *   - description: The effect description.
+ *
+ * @ingroup themeable
+ */
+#}
+{% if data.width and data.height -%}
+  {{ data.width|e }}×{{ data.height|e }}
+{%- else -%}
+  {% if data.width %}
+    {% trans %}
+      width {{ data.width|e }}
+    {% endtrans %}
+  {% elseif data.height %}
+    {% trans %}
+      height {{ data.height|e }}
+    {% endtrans %}
+  {% endif %}
+{%- endif %}
+
+{% if data.upscale %}
+  {% trans %}
+    (upscaling allowed)
+  {% endtrans %}
+{% endif %}
diff --git a/core/modules/image/tests/fixtures/update/image.image_style.test_scale_and_crop_upscale.yml b/core/modules/image/tests/fixtures/update/image.image_style.test_scale_and_crop_upscale.yml
new file mode 100644
index 0000000..118006a
--- /dev/null
+++ b/core/modules/image/tests/fixtures/update/image.image_style.test_scale_and_crop_upscale.yml
@@ -0,0 +1,13 @@
+uuid: b17c6242-453b-4fe4-8323-396488e1f043
+langcode: en
+status: true
+name: test_scale_and_crop_upscale
+label: test_scale_and_crop_upscale
+effects:
+  637b75a0-a80a-4bcc-8300-66994a27871d:
+    uuid: 637b75a0-a80a-4bcc-8300-66994a27871d
+    id: image_scale_and_crop
+    weight: 1
+    data:
+      width: 100
+      height: 100
diff --git a/core/modules/image/tests/fixtures/update/test_scale_and_crop_upscale.php b/core/modules/image/tests/fixtures/update/test_scale_and_crop_upscale.php
new file mode 100644
index 0000000..1e3f60d
--- /dev/null
+++ b/core/modules/image/tests/fixtures/update/test_scale_and_crop_upscale.php
@@ -0,0 +1,19 @@
+<?php
+
+/**
+ * @file
+ * Test fixture.
+ */
+
+use Drupal\Core\Database\Database;
+use Drupal\Core\Serialization\Yaml;
+
+$connection = Database::getConnection();
+
+$connection->insert('config')
+  ->fields(array(
+    'collection' => '',
+    'name' => 'image.style.test_scale_and_crop_upscale',
+    'data' => serialize(Yaml::decode(file_get_contents('core/modules/image/tests/fixtures/update/image.image_style.test_scale_and_crop_upscale.yml'))),
+  ))
+  ->execute();
diff --git a/core/modules/image/tests/src/Kernel/Migrate/d7/MigrateImageStylesTest.php b/core/modules/image/tests/src/Kernel/Migrate/d7/MigrateImageStylesTest.php
index 0903218..bd18a9d 100644
--- a/core/modules/image/tests/src/Kernel/Migrate/d7/MigrateImageStylesTest.php
+++ b/core/modules/image/tests/src/Kernel/Migrate/d7/MigrateImageStylesTest.php
@@ -32,7 +32,7 @@ protected function setUp() {
    * Test the image styles migration.
    */
   public function testImageStylesMigration() {
-    $this->assertEntity('custom_image_style_1', "Custom image style 1", ['image_scale_and_crop', 'image_desaturate'], [['width' => 55, 'height' => 55], []]);
+    $this->assertEntity('custom_image_style_1', "Custom image style 1", ['image_scale_and_crop', 'image_desaturate'], [['width' => 55, 'height' => 55, 'upscale' => FALSE], []]);
     $this->assertEntity('custom_image_style_2', "Custom image style 2", ['image_resize', 'image_rotate'], [['width' => 55, 'height' => 100], ['degrees' => 45, 'bgcolor' => '#FFFFFF', 'random' => FALSE]]);
     $this->assertEntity('custom_image_style_3', "Custom image style 3", ['image_scale', 'image_crop'], [['width' => 150, 'height' => NULL, 'upscale' => FALSE], ['width' => 50, 'height' => 50, 'anchor' => 'left-top']]);
   }
@@ -45,9 +45,9 @@ public function testImageStylesMigration() {
    * @param string $label
    *   The expected image style label.
    * @param array $expected_effect_plugins
-   *   An array of expected plugins attached to the image style entity
+   *   An array of expected plugins attached to the image style entity.
    * @param array $expected_effect_config
-   *   An array of expected configuration for each effect in the image style
+   *   An array of expected configuration for each effect in the image style.
    */
   protected function assertEntity($id, $label, array $expected_effect_plugins, array $expected_effect_config) {
     $style = ImageStyle::load($id);
diff --git a/core/themes/stable/templates/admin/image-scale-and-crop-summary.html.twig b/core/themes/stable/templates/admin/image-scale-and-crop-summary.html.twig
new file mode 100644
index 0000000..a5190e2
--- /dev/null
+++ b/core/themes/stable/templates/admin/image-scale-and-crop-summary.html.twig
@@ -0,0 +1,35 @@
+{#
+/**
+ * @file
+ * Theme override for a summary of an image scale and crop effect.
+ *
+ * Available variables:
+ * - data: The current configuration for this resize effect, including:
+ *   - width: The width of the resized image.
+ *   - height: The height of the resized image.
+ *   - upscale: If images larger than their original size can scale.
+ * - effect: The effect information, including:
+ *   - id: The effect identifier.
+ *   - label: The effect name.
+ *   - description: The effect description.
+ */
+#}
+{% if data.width and data.height -%}
+  {{ data.width|e }}×{{ data.height|e }}
+{%- else -%}
+  {% if data.width %}
+    {% trans %}
+      width {{ data.width|e }}
+    {% endtrans %}
+  {% elseif data.height %}
+    {% trans %}
+      height {{ data.height|e }}
+    {% endtrans %}
+  {% endif %}
+{%- endif %}
+
+{% if data.upscale %}
+  {% trans %}
+    (upscaling allowed)
+  {% endtrans %}
+{% endif %}
