diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -1811,6 +1811,7 @@
     'PhabricatorBcryptPasswordHasher' => 'infrastructure/util/password/PhabricatorBcryptPasswordHasher.php',
     'PhabricatorBinariesSetupCheck' => 'applications/config/check/PhabricatorBinariesSetupCheck.php',
     'PhabricatorBitbucketAuthProvider' => 'applications/auth/provider/PhabricatorBitbucketAuthProvider.php',
+    'PhabricatorBoardLayoutEngine' => 'applications/project/engine/PhabricatorBoardLayoutEngine.php',
     'PhabricatorBot' => 'infrastructure/daemon/bot/PhabricatorBot.php',
     'PhabricatorBotChannel' => 'infrastructure/daemon/bot/target/PhabricatorBotChannel.php',
     'PhabricatorBotDebugLogHandler' => 'infrastructure/daemon/bot/handler/PhabricatorBotDebugLogHandler.php',
@@ -6035,6 +6036,7 @@
     'PhabricatorBcryptPasswordHasher' => 'PhabricatorPasswordHasher',
     'PhabricatorBinariesSetupCheck' => 'PhabricatorSetupCheck',
     'PhabricatorBitbucketAuthProvider' => 'PhabricatorOAuth1AuthProvider',
+    'PhabricatorBoardLayoutEngine' => 'Phobject',
     'PhabricatorBot' => 'PhabricatorDaemon',
     'PhabricatorBotChannel' => 'PhabricatorBotTarget',
     'PhabricatorBotDebugLogHandler' => 'PhabricatorBotHandler',
diff --git a/src/applications/project/controller/PhabricatorProjectMoveController.php b/src/applications/project/controller/PhabricatorProjectMoveController.php
--- a/src/applications/project/controller/PhabricatorProjectMoveController.php
+++ b/src/applications/project/controller/PhabricatorProjectMoveController.php
@@ -26,6 +26,8 @@
       return new Aphront404Response();
     }
 
+    $board_phid = $project->getPHID();
+
     $object = id(new ManiphestTaskQuery())
       ->setViewer($viewer)
       ->withPHIDs(array($object_phid))
@@ -54,11 +56,14 @@
       return new Aphront404Response();
     }
 
-    $positions = id(new PhabricatorProjectColumnPositionQuery())
+    $engine = id(new PhabricatorBoardLayoutEngine())
       ->setViewer($viewer)
-      ->withColumns($columns)
-      ->withObjectPHIDs(array($object_phid))
-      ->execute();
+      ->setBoardPHIDs(array($board_phid))
+      ->setObjectPHIDs(array($object_phid))
+      ->executeLayout();
+
+    $columns = $engine->getObjectColumns($board_phid, $object_phid);
+    $old_column_phids = mpull($columns, 'getPHID');
 
     $xactions = array();
 
@@ -80,7 +85,7 @@
         ) + $order_params)
       ->setOldValue(
         array(
-          'columnPHIDs' => mpull($positions, 'getColumnPHID'),
+          'columnPHIDs' => $old_column_phids,
           'projectPHID' => $column->getProjectPHID(),
         ));
 
diff --git a/src/applications/project/engine/PhabricatorBoardLayoutEngine.php b/src/applications/project/engine/PhabricatorBoardLayoutEngine.php
new file mode 100644
--- /dev/null
+++ b/src/applications/project/engine/PhabricatorBoardLayoutEngine.php
@@ -0,0 +1,187 @@
+<?php
+
+final class PhabricatorBoardLayoutEngine extends Phobject {
+
+  private $viewer;
+  private $boardPHIDs;
+  private $objectPHIDs;
+  private $boards;
+  private $columnMap;
+  private $objectColumnMap = array();
+  private $boardLayout = array();
+
+  public function setViewer(PhabricatorUser $viewer) {
+    $this->viewer = $viewer;
+    return $this;
+  }
+
+  public function getViewer() {
+    return $this->viewer;
+  }
+
+  public function setBoardPHIDs(array $board_phids) {
+    $this->boardPHIDs = $board_phids;
+    return $this;
+  }
+
+  public function getBoardPHIDs() {
+    return $this->boardPHIDs;
+  }
+
+  public function setObjectPHIDs(array $object_phids) {
+    $this->objectPHIDs = $object_phids;
+    return $this;
+  }
+
+  public function getObjectPHIDs() {
+    return $this->objectPHIDs;
+  }
+
+  public function executeLayout() {
+    $viewer = $this->getViewer();
+
+    $boards = $this->loadBoards();
+    if (!$boards) {
+      return $this;
+    }
+
+    $columns = $this->loadColumns($boards);
+    $positions = $this->loadPositions($boards);
+
+    foreach ($boards as $board_phid => $board) {
+      $board_columns = idx($columns, $board_phid);
+
+      // Don't layout boards with no columns. These boards need to be formally
+      // created first.
+      if (!$columns) {
+        continue;
+      }
+
+      $board_positions = idx($positions, $board_phid, array());
+
+      $this->layoutBoard($board, $board_columns, $board_positions);
+    }
+
+    return $this;
+  }
+
+  public function getObjectColumns($board_phid, $object_phid) {
+    $board_map = idx($this->objectColumnMap, $board_phid, array());
+
+    $column_phids = idx($board_map, $object_phid);
+    if (!$column_phids) {
+      return array();
+    }
+
+    return array_select_keys($this->columnMap, $column_phids);
+  }
+
+  private function loadBoards() {
+    $viewer = $this->getViewer();
+    $board_phids = $this->getBoardPHIDs();
+
+    $boards = id(new PhabricatorObjectQuery())
+      ->setViewer($viewer)
+      ->withPHIDs($board_phids)
+      ->execute();
+    $boards = mpull($boards, null, 'getPHID');
+
+    foreach ($boards as $key => $board) {
+      if (!$board->getHasWorkboard()) {
+        unset($boards[$key]);
+      }
+    }
+
+    return $boards;
+  }
+
+  private function loadColumns(array $boards) {
+    $viewer = $this->getViewer();
+
+    $columns = id(new PhabricatorProjectColumnQuery())
+      ->setViewer($viewer)
+      ->withProjectPHIDs(array_keys($boards))
+      ->execute();
+    $columns = msort($columns, 'getSequence');
+    $columns = mpull($columns, null, 'getPHID');
+
+    $this->columnMap = $columns;
+    $columns = mgroup($columns, 'getProjectPHID');
+
+    return $columns;
+  }
+
+  private function loadPositions(array $boards) {
+    $viewer = $this->getViewer();
+
+    $positions = id(new PhabricatorProjectColumnPositionQuery())
+      ->setViewer($viewer)
+      ->withBoardPHIDs(array_keys($boards))
+      ->withObjectPHIDs($this->getObjectPHIDs())
+      ->execute();
+    $positions = msort($positions, 'getOrderingKey');
+    $positions = mgroup($positions, 'getBoardPHID');
+
+    return $positions;
+  }
+
+  private function layoutBoard(
+    $board,
+    array $columns,
+    array $positions) {
+
+    $board_phid = $board->getPHID();
+    $position_groups = mgroup($positions, 'getObjectPHID');
+
+    foreach ($columns as $column) {
+      if ($column->isDefaultColumn()) {
+        $default_phid = $column->getPHID();
+        break;
+      }
+    }
+
+    $layout = array();
+
+    $object_phids = $this->getObjectPHIDs();
+    foreach ($object_phids as $object_phid) {
+      $positions = idx($position_groups, $object_phid, array());
+
+      // Remove any positions in columns which no longer exist.
+      foreach ($positions as $key => $position) {
+        $column_phid = $position->getColumnPHID();
+        if (empty($columns[$column_phid])) {
+          unset($positions[$key]);
+        }
+      }
+
+      // If the object has no position, put it on the default column.
+      if (!$positions) {
+        $new_position = id(new PhabricatorProjectColumnPosition())
+          ->setBoardPHID($board_phid)
+          ->setColumnPHID($default_phid)
+          ->setObjectPHID($object_phid)
+          ->setSequence(0);
+        $positions = array(
+          $new_position,
+        );
+      }
+
+      foreach ($positions as $position) {
+        $column_phid = $position->getColumnPHID();
+        $layout[$column_phid][$object_phid] = $position;
+      }
+    }
+
+    foreach ($layout as $column_phid => $map) {
+      $map = msort($map, 'getOrderingKey');
+      $layout[$column_phid] = $map;
+
+      foreach ($map as $object_phid => $position) {
+        $this->objectColumnMap[$board_phid][$object_phid][] = $column_phid;
+      }
+    }
+
+    $this->boardLayout[$board_phid] = $layout;
+  }
+
+}
diff --git a/src/applications/project/events/PhabricatorProjectUIEventListener.php b/src/applications/project/events/PhabricatorProjectUIEventListener.php
--- a/src/applications/project/events/PhabricatorProjectUIEventListener.php
+++ b/src/applications/project/events/PhabricatorProjectUIEventListener.php
@@ -49,37 +49,24 @@
 
     $annotations = array();
     if ($handles && $can_appear_on_boards) {
+      $engine = id(new PhabricatorBoardLayoutEngine())
+        ->setViewer($user)
+        ->setBoardPHIDs($project_phids)
+        ->setObjectPHIDs(array($object->getPHID()))
+        ->executeLayout();
 
       // TDOO: Generalize this UI and move it out of Maniphest.
-
       require_celerity_resource('maniphest-task-summary-css');
 
-      $positions_query = id(new PhabricatorProjectColumnPositionQuery())
-        ->setViewer($user)
-        ->withBoardPHIDs($project_phids)
-        ->withObjectPHIDs(array($object->getPHID()))
-        ->needColumns(true);
-
-      // This is important because positions will be created "on demand"
-      // based on the set of columns. If we don't specify it, positions
-      // won't be created.
-      $columns = id(new PhabricatorProjectColumnQuery())
-        ->setViewer($user)
-        ->withProjectPHIDs($project_phids)
-        ->execute();
-      if ($columns) {
-        $positions_query->withColumns($columns);
-      }
-      $positions = $positions_query->execute();
-      $positions = mpull($positions, null, 'getBoardPHID');
-
       foreach ($project_phids as $project_phid) {
         $handle = $handles[$project_phid];
 
-        $position = idx($positions, $project_phid);
-        if ($position) {
-          $column = $position->getColumn();
+        $columns = $engine->getObjectColumns(
+          $project_phid,
+          $object->getPHID());
 
+        $annotation = array();
+        foreach ($columns as $column) {
           $column_name = pht('(%s)', $column->getDisplayName());
           $column_link = phutil_tag(
             'a',
@@ -89,9 +76,13 @@
             ),
             $column_name);
 
+          $annotation[] = $column_link;
+        }
+
+        if ($annotation) {
           $annotations[$project_phid] = array(
             ' ',
-            $column_link,
+            phutil_implode_html(', ', $annotation),
           );
         }
       }
diff --git a/src/applications/project/storage/PhabricatorProjectColumnPosition.php b/src/applications/project/storage/PhabricatorProjectColumnPosition.php
--- a/src/applications/project/storage/PhabricatorProjectColumnPosition.php
+++ b/src/applications/project/storage/PhabricatorProjectColumnPosition.php
@@ -41,6 +41,10 @@
   }
 
   public function getOrderingKey() {
+    if (!$this->getID()) {
+      return 0;
+    }
+
     // Low sequence numbers go above high sequence numbers.
     // High position IDs go above low position IDs.
     // Broadly, this makes newly added stuff float to the top.