diff --git a/core/lib/Drupal/Core/Database/Query/Select.php b/core/lib/Drupal/Core/Database/Query/Select.php
index a7e340b..b269410 100644
--- a/core/lib/Drupal/Core/Database/Query/Select.php
+++ b/core/lib/Drupal/Core/Database/Query/Select.php
@@ -39,7 +39,7 @@ class Select extends Query implements SelectInterface {
    *   'type' => $join_type (one of INNER, LEFT OUTER, RIGHT OUTER),
    *   'table' => $table,
    *   'alias' => $alias_of_the_table,
-   *   'condition' => $condition_clause_on_which_to_join,
+   *   'condition' => $join_condition (string or Condition object),
    *   'arguments' => $array_of_arguments_for_placeholders_in_the condition.
    *   'all_fields' => TRUE to SELECT $alias.*, FALSE or NULL otherwise.
    * )
@@ -47,6 +47,10 @@ class Select extends Query implements SelectInterface {
    * If $table is a string, it is taken as the name of a table. If it is
    * a Select query object, it is taken as a subquery.
    *
+   * If $join_condition is a Condition object, any arguments should be
+   * incorporated into the object; a separate array of arguments does not
+   * need to be provided.
+   *
    * @var array
    */
   protected $tables = array();
@@ -196,6 +200,10 @@ public function arguments() {
       if ($table['table'] instanceof SelectInterface) {
         $args += $table['table']->arguments();
       }
+      // If the join condition is an object, grab its arguments recursively.
+      if (!empty($table['condition']) && $table['condition'] instanceof ConditionInterface) {
+        $args += $table['condition']->arguments();
+      }
     }

     foreach ($this->expressions as $expression) {
@@ -225,6 +233,10 @@ public function compile(Connection $connection, PlaceholderInterface $queryPlace
       if ($table['table'] instanceof SelectInterface) {
         $table['table']->compile($connection, $queryPlaceholder);
       }
+      // Make sure join conditions are also compiled.
+      if (!empty($table['condition']) && $table['condition'] instanceof ConditionInterface) {
+        $table['condition']->compile($connection, $queryPlaceholder);
+      }
     }

     // If there are any dependent queries to UNION, compile it recursively.
@@ -248,6 +260,11 @@ public function compiled() {
           return FALSE;
         }
       }
+      if (!empty($table['condition']) && $table['condition'] instanceof ConditionInterface) {
+        if (!$table['condition']->compiled()) {
+          return FALSE;
+        }
+      }
     }

     foreach ($this->union as $union) {
@@ -822,7 +839,7 @@ public function __toString() {
       $query .= $table_string . ' ' . $this->connection->escapeTable($table['alias']);

       if (!empty($table['condition'])) {
-        $query .= ' ON ' . $table['condition'];
+        $query .= ' ON ' . (string) $table['condition'];
       }
     }

diff --git a/core/tests/Drupal/KernelTests/Core/Database/SelectComplexTest.php b/core/tests/Drupal/KernelTests/Core/Database/SelectComplexTest.php
index cadf178..ef2fedf 100644
--- a/core/tests/Drupal/KernelTests/Core/Database/SelectComplexTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Database/SelectComplexTest.php
@@ -375,4 +375,50 @@ function testSelectWithRowCount() {
     $this->assertTrue($exception, 'Exception was thrown');
   }

+  /**
+   * Test that join conditions can use Condition objects.
+   */
+  function testJoinConditionObject() {
+    // Same test as testDefaultJoin, but with a Condition object.
+    $query = db_select('test_task', 't');
+    $join_cond = db_and()->where('t.pid = p.id');
+    $people_alias = $query->join('test', 'p', $join_cond);
+    $name_field = $query->addField($people_alias, 'name', 'name');
+    $query->addField('t', 'task', 'task');
+    $priority_field = $query->addField('t', 'priority', 'priority');
+
+    $query->orderBy($priority_field);
+    $result = $query->execute();
+
+    $num_records = 0;
+    $last_priority = 0;
+    foreach ($result as $record) {
+      $num_records++;
+      $this->assertTrue($record->$priority_field >= $last_priority, 'Results returned in correct order.');
+      $this->assertNotEqual($record->$name_field, 'Ringo', 'Taskless person not selected.');
+      $last_priority = $record->$priority_field;
+    }
+
+    $this->assertEqual($num_records, 7, 'Returned the correct number of rows.');
+
+    // Test a condition object that creates placeholders.
+    $t1_name = 'John';
+    $t2_name = 'George';
+    $join_cond = db_and()
+      ->condition('t1.name', $t1_name)
+      ->condition('t2.name', $t2_name);
+    $query = db_select('test', 't1');
+    $query->innerJoin('test', 't2', $join_cond);
+    $query->addField('t1', 'name', 't1_name');
+    $query->addField('t2', 'name', 't2_name');
+
+    $num_records = $query->countQuery()->execute()->fetchField();
+    $this->assertEqual($num_records, 1, 'Query expected to return 1 row. Actual: ' . $num_records);
+    if ($num_records==1) {
+      $record = $query->execute()->fetchObject();
+      $this->assertEqual($record->t1_name, $t1_name, 'Query expected to retrieve name ' . $t1_name . ' from table t1. Actual: ' . $record->t1_name);
+      $this->assertEqual($record->t2_name, $t2_name, 'Query expected to retrieve name ' . $t2_name . ' from table t2. Actual: ' . $record->t2_name);
+    }
+  }
+
 }
