diff --git a/core/modules/views/config/schema/views.filter.schema.yml b/core/modules/views/config/schema/views.filter.schema.yml
index 44a5661..3215f1d 100644
--- a/core/modules/views/config/schema/views.filter.schema.yml
+++ b/core/modules/views/config/schema/views.filter.schema.yml
@@ -31,6 +31,17 @@ views.filter.combine:
         type: string
         label: 'Field'
 
+views.filter.compare:
+  type: views_filter
+  label: 'Compare'
+  mapping:
+    left_field:
+      type: string
+      label: 'Left field'
+    right_field:
+      type: string
+      label: 'Right field'
+
 views.filter_value.date:
   type: views.filter_value.numeric
   label: 'Date'
diff --git a/core/modules/views/src/Plugin/views/filter/Compare.php b/core/modules/views/src/Plugin/views/filter/Compare.php
new file mode 100644
index 0000000..8e610cd
--- /dev/null
+++ b/core/modules/views/src/Plugin/views/filter/Compare.php
@@ -0,0 +1,142 @@
+<?php
+
+namespace Drupal\views\Plugin\views\filter;
+
+use Drupal\Component\Render\FormattableMarkup;
+use Drupal\Core\Form\FormStateInterface;
+
+/**
+ * Defines a filter plugin to compare different fields.
+ *
+ * @ingroup views_filter_handlers
+ *
+ * @PluginID("compare")
+ */
+class Compare extends FilterPluginBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function canExpose() {
+    return FALSE;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function usesGroupBy() {
+    return FALSE;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function defineOptions() {
+    $options = parent::defineOptions();
+
+    $options['left_field'] = ['default' => ''];
+    $options['right_field'] = ['default' => ''];
+
+    return $options;
+  }
+
+  /**
+   * Provides a list of all operators.
+   *
+   * @return array
+   *   An array of operators.
+   */
+  protected function fieldsOperatorOptions() {
+    return [
+      '<' => $this->t('Is less than'),
+      '<=' => $this->t('Is less than or equal to'),
+      '=' => $this->t('Is equal to'),
+      '<>' => $this->t('Is not equal to'),
+      '>=' => $this->t('Is greater than or equal to'),
+      '>' => $this->t('Is greater than')
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
+    parent::buildOptionsForm($form, $form_state);
+
+    $field_options = $this->displayHandler->getFieldLabels();
+    // Filter out the views table as it will not be filterable.
+    $this->view->initHandlers();
+    foreach (array_keys($field_options) as $id) {
+      if ($this->view->field[$id]->table == 'views') {
+        unset($field_options[$id]);
+      }
+    }
+
+    $form['left_field'] = [
+      '#type' => 'select',
+      '#title' => $this->t('Left field'),
+      '#default_value' => $this->options['left_field'],
+      '#options' => $field_options,
+      '#weight' => -3,
+    ];
+
+    $form['operator'] = [
+      '#type' => 'select',
+      '#title' => $this->t('Operator'),
+      '#default_value' => $this->options['operator'],
+      '#options' => $this->fieldsOperatorOptions(),
+      '#weight' => -2,
+    ];
+
+    $form['right_field'] = [
+      '#type' => 'select',
+      '#title' => $this->t('Right field'),
+      '#default_value' => $this->options['right_field'],
+      '#options' => $field_options,
+      '#weight' => -1,
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function adminSummary() {
+    return new FormattableMarkup('@left_field @operator @right_field', ['@left_field' => $this->options['left_field'], '@operator' => $this->options['operator'], '@right_field' => $this->options['right_field']]);
+  }
+
+  /**
+   * Add this filter to the query.
+   *
+   * Builds extra condition from existing fields (from existing joins).
+   */
+  public function query() {
+    $left = $this->options['left_field'];
+    $right = $this->options['right_field'];
+
+    // Get all existing field handlers.
+    $field_handlers = $this->displayHandler->getHandlers('field');
+
+    // Make sure the selected fields still exist.
+    if (!isset($field_handlers[$left], $field_handlers[$right])) {
+      return;
+    }
+
+    // Get the left table and field.
+    /** @var \Drupal\views\Plugin\views\filter\FilterPluginBase $left_handler */
+    $left_handler = $field_handlers[$left];
+    $left_handler->setRelationship();
+    $left_table_alias = $this->query->ensureTable($left_handler->table, $left_handler->relationship);
+
+    // Get the right table and field.
+    /** @var \Drupal\views\Plugin\views\filter\FilterPluginBase $right_handler */
+    $right_handler = $field_handlers[$right];
+    $right_handler->setRelationship();
+    $right_table_alias = $this->query->ensureTable($right_handler->table, $right_handler->relationship);
+
+    // Build piece of SQL.
+    $snippet = $left_table_alias . '.' . $left_handler->realField . ' ' . $this->options['operator'] . ' ' . $right_table_alias . '.' . $right_handler->realField;
+
+    $this->query->addWhereExpression($this->options['group'], $snippet);
+  }
+
+}
diff --git a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_filter_compare.yml b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_filter_compare.yml
new file mode 100644
index 0000000..d9fd145
--- /dev/null
+++ b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_filter_compare.yml
@@ -0,0 +1,59 @@
+base_table: views_test_data
+core: '8'
+description: ''
+status: '1'
+display:
+  default:
+    display_options:
+      defaults:
+        fields: '0'
+        filters: '0'
+        pager: '0'
+        sorts: '0'
+      fields:
+        created:
+          field: created
+          id: created
+          relationship: none
+          table: views_test_data
+          plugin_id: numeric
+        age:
+          field: age
+          id: age
+          relationship: none
+          table: views_test_data
+          plugin_id: numeric
+        name:
+          field: name
+          id: name
+          relationship: none
+          table: views_test_data
+          plugin_id: string
+      pager:
+        options:
+          offset: '0'
+        type: none
+      filters:
+        fields_compare:
+          table: views
+          field: fields_compare
+          id: fields_compare
+          plugin_id: compare
+          left_field: age
+          right_field: created
+          operator: '='
+      sorts:
+        id:
+          field: id
+          id: id
+          order: ASC
+          relationship: none
+          table: views_test_data
+          plugin_id: numeric
+    display_plugin: default
+    display_title: Master
+    id: default
+    position: '0'
+label: 'Test view'
+id: test_filter_compare
+tag: ''
diff --git a/core/modules/views/tests/src/Kernel/Handler/FilterCompareTest.php b/core/modules/views/tests/src/Kernel/Handler/FilterCompareTest.php
new file mode 100644
index 0000000..92f0e4b
--- /dev/null
+++ b/core/modules/views/tests/src/Kernel/Handler/FilterCompareTest.php
@@ -0,0 +1,119 @@
+<?php
+
+namespace Drupal\Tests\views\Kernel\Handler;
+
+use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
+use Drupal\views\Views;
+
+/**
+ * Tests the combine filter handler.
+ *
+ * @see \Drupal\views\Plugin\views\filter\Compare
+ */
+class FilterCompareTest extends ViewsKernelTestBase {
+
+  /**
+   * The column map used in the test.
+   *
+   * @var array
+   */
+  protected $columnMap = [
+    'views_test_data_name' => 'name',
+  ];
+
+  /**
+   * Views used by this test.
+   *
+   * @var array
+   */
+  public static $testViews = ['test_filter_compare'];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function dataSet() {
+    // Setup age/created so comparing fields can be tested.
+    $data = parent::dataSet();
+
+    $data[0]['age'] = $data[0]['created'];
+    $data[1]['age'] = $data[1]['created'] + 1000;
+    $data[2]['age'] = $data[2]['created'] + 1;
+    $data[3]['age'] = $data[3]['created'] - 1;
+    $data[4]['age'] = $data[4]['created'] - 1000;
+
+    return $data;
+  }
+
+  /**
+   * Tests the compare handler.
+   */
+  public function testCompare() {
+    $view = Views::getView('test_filter_compare');
+
+    // Test the equality operator.
+    $this->executeView($view);
+    $this->assertIdenticalResultset($view, [['name' => 'John']], $this->columnMap);
+    $view->destroy();
+
+    $tests = [];
+    $tests[] = [
+      '=', [
+      ['name' => 'John'],
+      ]
+    ];
+
+    $tests[] = [
+      '!=', [
+      ['name' => 'George'],
+      ['name' => 'Ringo'],
+      ['name' => 'Paul'],
+      ['name' => 'Meredith']
+      ]
+    ];
+
+    $tests[] = [
+      '>', [
+      ['name' => 'George'],
+      ['name' => 'Ringo'],
+      ]
+    ];
+
+    $tests[] = [
+      '>=', [
+      ['name' => 'John'],
+      ['name' => 'George'],
+      ['name' => 'Ringo'],
+      ]
+    ];
+
+    $tests[] = [
+      '<', [
+      ['name' => 'Paul'],
+      ['name' => 'Meredith'],
+      ]
+    ];
+
+    $tests[] = [
+      '<=', [
+      ['name' => 'John'],
+      ['name' => 'Paul'],
+      ['name' => 'Meredith'],
+      ]
+    ];
+
+    foreach ($tests as $parts) {
+      list($operator, $expected) = $parts;
+
+      $view->initDisplay();
+      $item = $view->getHandler('default', 'filter', 'fields_compare');
+      $item['operator'] = $operator;
+      $view->setHandler('default', 'filter', 'fields_compare', $item);
+
+      $this->executeView($view);
+      $this->assertIdenticalResultset($view, $expected, $this->columnMap);
+      $view->destroy();
+    }
+
+  }
+
+}
diff --git a/core/modules/views/views.views.inc b/core/modules/views/views.views.inc
index aca4b8a..9f77943 100644
--- a/core/modules/views/views.views.inc
+++ b/core/modules/views/views.views.inc
@@ -120,6 +120,14 @@ function views_views_data() {
     ),
   );
 
+  $data['views']['fields_compare'] = array(
+    'title' => t('Fields comparison'),
+    'help' => t('Compare two fields to filter the result of a view.'),
+    'filter' => array(
+      'id' => 'compare',
+    )
+  );
+
   $data['views']['dropbutton'] = array(
     'title' => t('Dropbutton'),
     'help' => t('Display fields in a dropbutton.'),
