diff --git a/src/Plugin/Field/FieldWidget/InlineParagraphsWidget.php b/src/Plugin/Field/FieldWidget/InlineParagraphsWidget.php
index 1402b5f..5e018d1 100644
--- a/src/Plugin/Field/FieldWidget/InlineParagraphsWidget.php
+++ b/src/Plugin/Field/FieldWidget/InlineParagraphsWidget.php
@@ -850,30 +850,33 @@ class InlineParagraphsWidget extends WidgetBase {
     $field_state['real_item_count'] = $this->realItemCount;
     static::setWidgetState($this->fieldParents, $field_name, $form_state, $field_state);
 
+    $elements += [
+      '#element_validate' => [[$this, 'multipleElementValidate']],
+      '#required' => $this->fieldDefinition->isRequired(),
+      '#field_name' => $field_name,
+      '#cardinality' => $cardinality,
+      '#max_delta' => $max - 1,
+    ];
+
     if ($this->realItemCount > 0) {
       $elements += array(
         '#theme' => 'field_multiple_value_form',
-        '#field_name' => $field_name,
-        '#cardinality' => $cardinality,
         '#cardinality_multiple' => $is_multiple,
-        '#required' => $this->fieldDefinition->isRequired(),
         '#title' => $title,
         '#description' => $description,
-        '#max_delta' => $max-1,
       );
     }
     else {
+      $classes = $this->fieldDefinition->isRequired() ? ['form-required'] : [];
       $elements += [
         '#type' => 'container',
         '#theme_wrappers' => ['container'],
-        '#field_name' => $field_name,
-        '#cardinality' => $cardinality,
         '#cardinality_multiple' => TRUE,
-        '#max_delta' => $max-1,
         'title' => [
           '#type' => 'html_tag',
           '#tag' => 'strong',
           '#value' => $title,
+          '#attributes' => ['class' => $classes],
         ],
         'text' => [
           '#type' => 'container',
@@ -881,7 +884,7 @@ class InlineParagraphsWidget extends WidgetBase {
             '#markup' => $this->t('No @title added yet.', ['@title' => $this->getSetting('title')]),
             '#prefix' => '<em>',
             '#suffix' => '</em>',
-          ]
+          ],
         ],
       ];
 
@@ -1239,6 +1242,31 @@ class InlineParagraphsWidget extends WidgetBase {
   /**
    * {@inheritdoc}
    */
+  public function multipleElementValidate($element, FormStateInterface $form_state, $form) {
+    $field_name = $this->fieldDefinition->getName();
+    $widget_state = static::getWidgetState($element['#field_parents'], $field_name, $form_state);
+
+    $remove_mode_item_count = 0;
+    if (isset($widget_state['paragraphs'])) {
+      foreach ($widget_state['paragraphs'] as $paragraph) {
+        if ($paragraph['mode'] == 'remove') {
+          $remove_mode_item_count++;
+        }
+      }
+    }
+
+    $non_remove_mode_item_count = $widget_state['real_item_count'] - $remove_mode_item_count ;
+
+    if ($element['#required'] && $non_remove_mode_item_count < 1) {
+      $form_state->setError($element, t('@name field is required.', ['@name' => $this->fieldDefinition->getLabel()]));
+    }
+
+    static::setWidgetState($element['#field_parents'], $field_name, $form_state, $widget_state);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function massageFormValues(array $values, array $form, FormStateInterface $form_state) {
     $field_name = $this->fieldDefinition->getName();
     $widget_state = static::getWidgetState($form['#parents'], $field_name, $form_state);
diff --git a/src/Plugin/Field/FieldWidget/ParagraphsWidget.php b/src/Plugin/Field/FieldWidget/ParagraphsWidget.php
index 78fec4d..4204816 100644
--- a/src/Plugin/Field/FieldWidget/ParagraphsWidget.php
+++ b/src/Plugin/Field/FieldWidget/ParagraphsWidget.php
@@ -843,30 +843,33 @@ class ParagraphsWidget extends WidgetBase {
     $field_state['real_item_count'] = $this->realItemCount;
     static::setWidgetState($this->fieldParents, $field_name, $form_state, $field_state);
 
+    $elements += [
+      '#element_validate' => [[$this, 'multipleElementValidate']],
+      '#required' => $this->fieldDefinition->isRequired(),
+      '#field_name' => $field_name,
+      '#cardinality' => $cardinality,
+      '#max_delta' => $max - 1,
+    ];
+
     if ($this->realItemCount > 0) {
       $elements += array(
         '#theme' => 'field_multiple_value_form',
-        '#field_name' => $field_name,
-        '#cardinality' => $cardinality,
         '#cardinality_multiple' => $is_multiple,
-        '#required' => $this->fieldDefinition->isRequired(),
         '#title' => $title,
         '#description' => $description,
-        '#max_delta' => $max-1,
       );
     }
     else {
+      $classes = $this->fieldDefinition->isRequired() ? ['form-required'] : [];
       $elements += [
         '#type' => 'container',
         '#theme_wrappers' => ['container'],
-        '#field_name' => $field_name,
-        '#cardinality' => $cardinality,
         '#cardinality_multiple' => TRUE,
-        '#max_delta' => $max-1,
         'title' => [
           '#type' => 'html_tag',
           '#tag' => 'strong',
           '#value' => $title,
+          '#attributes' => ['class' => $classes],
         ],
         'text' => [
           '#type' => 'container',
@@ -874,7 +877,7 @@ class ParagraphsWidget extends WidgetBase {
             '#markup' => $this->t('No @title added yet.', ['@title' => $this->getSetting('title')]),
             '#prefix' => '<em>',
             '#suffix' => '</em>',
-          ]
+          ],
         ],
       ];
 
@@ -1239,6 +1242,31 @@ class ParagraphsWidget extends WidgetBase {
   /**
    * {@inheritdoc}
    */
+  public function multipleElementValidate($element, FormStateInterface $form_state, $form) {
+    $field_name = $this->fieldDefinition->getName();
+    $widget_state = static::getWidgetState($element['#field_parents'], $field_name, $form_state);
+
+    $remove_mode_item_count = 0;
+    if (isset($widget_state['paragraphs'])) {
+      foreach ($widget_state['paragraphs'] as $paragraph) {
+        if ($paragraph['mode'] == 'remove') {
+          $remove_mode_item_count++;
+        }
+      }
+    }
+
+    $non_remove_mode_item_count = $widget_state['real_item_count'] - $remove_mode_item_count ;
+
+    if ($element['#required'] && $non_remove_mode_item_count < 1) {
+      $form_state->setError($element, t('@name field is required.', ['@name' => $this->fieldDefinition->getLabel()]));
+    }
+
+    static::setWidgetState($element['#field_parents'], $field_name, $form_state, $widget_state);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function massageFormValues(array $values, array $form, FormStateInterface $form_state) {
     $field_name = $this->fieldDefinition->getName();
     $widget_state = static::getWidgetState($form['#parents'], $field_name, $form_state);
diff --git a/src/Tests/Classic/ParagraphsUiTest.php b/src/Tests/Classic/ParagraphsUiTest.php
new file mode 100644
index 0000000..a0d19d7
--- /dev/null
+++ b/src/Tests/Classic/ParagraphsUiTest.php
@@ -0,0 +1,65 @@
+<?php
+
+namespace Drupal\paragraphs\Tests\Classic;
+
+use Drupal\field_ui\Tests\FieldUiTestTrait;
+
+/**
+ * Tests the Paragraphs user interface.
+ *
+ * @group paragraphs
+ */
+class ParagraphsUiTest extends ParagraphsTestBase {
+
+  use FieldUiTestTrait;
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = [
+    'paragraphs_demo',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+  }
+
+  /**
+   * Tests displaying an error message a required paragraph field that is empty.
+   */
+  public function testEmptyRequiredField() {
+    $admin_user = $this->drupalCreateUser([
+      'administer node fields',
+      'administer paragraph form display',
+      'administer node form display',
+      'create paragraphed_content_demo content',
+      'edit any paragraphed_content_demo content',
+    ]);
+    $this->drupalLogin($admin_user);
+    // Add required field to paragraphed content type.
+    $field_title = 'Content Test';
+    $this->drupalPostForm('admin/structure/types/manage/paragraphed_content_demo/fields/add-field', [
+      'new_storage_type' => 'field_ui:entity_reference_revisions:paragraph',
+      'label' => $field_title,
+      'field_name' => 'content',
+    ], t('Save and continue'));
+    $this->drupalPostForm(NULL, [], t('Save field settings'));
+    $edit = [
+      'required' => TRUE,
+    ];
+    $this->drupalPostForm(NULL, $edit, 'Save settings');
+    $this->assertText('Saved ' . $field_title . ' configuration.');
+
+    // Create paragraph with empty required field.
+    $title = 'Empty';
+    $this->drupalGet('node/add/paragraphed_content_demo');
+    $this->drupalPostForm(NULL, ['title[0][value]' => $title], t('Save'));
+    $this->assertText($field_title . ' field is required');
+  }
+
+}
diff --git a/src/Tests/Experimental/ParagraphsExperimentalUiTest.php b/src/Tests/Experimental/ParagraphsExperimentalUiTest.php
new file mode 100644
index 0000000..c79dd40
--- /dev/null
+++ b/src/Tests/Experimental/ParagraphsExperimentalUiTest.php
@@ -0,0 +1,65 @@
+<?php
+
+namespace Drupal\paragraphs\Tests\Experimental;
+
+use Drupal\field_ui\Tests\FieldUiTestTrait;
+
+/**
+ * Tests the Paragraphs user interface.
+ *
+ * @group paragraphs
+ */
+class ParagraphsExperimentalUiTest extends ParagraphsExperimentalTestBase {
+
+  use FieldUiTestTrait;
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = [
+    'paragraphs_demo',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+  }
+
+  /**
+   * Tests displaying an error message a required paragraph field that is empty.
+   */
+  public function testEmptyRequiredField() {
+    $admin_user = $this->drupalCreateUser([
+      'administer node fields',
+      'administer paragraph form display',
+      'administer node form display',
+      'create paragraphed_content_demo content',
+      'edit any paragraphed_content_demo content',
+    ]);
+    $this->drupalLogin($admin_user);
+    // Add required field to paragraphed content type.
+    $field_title = 'Content Test';
+    $this->drupalPostForm('admin/structure/types/manage/paragraphed_content_demo/fields/add-field', [
+      'new_storage_type' => 'field_ui:entity_reference_revisions:paragraph',
+      'label' => $field_title,
+      'field_name' => 'content',
+    ], t('Save and continue'));
+    $this->drupalPostForm(NULL, [], t('Save field settings'));
+    $edit = [
+      'required' => TRUE,
+    ];
+    $this->drupalPostForm(NULL, $edit, 'Save settings');
+    $this->assertText('Saved ' . $field_title . ' configuration.');
+
+    // Create paragraph with empty required field.
+    $title = 'Empty';
+    $this->drupalGet('node/add/paragraphed_content_demo');
+    $this->drupalPostForm(NULL, ['title[0][value]' => $title], t('Save'));
+    $this->assertText($field_title . ' field is required');
+  }
+
+}
