diff --git a/addon/-private/collapse-tree.js b/addon/-private/collapse-tree.js
index d982432df..f8b86c888 100644
--- a/addon/-private/collapse-tree.js
+++ b/addon/-private/collapse-tree.js
@@ -27,6 +27,7 @@ export class TableRowMeta extends EmberObject {
   */
   _cellMetaCache = new Map();
   _isCollapsed = false;
+  _lastKnownIndex = null;
 
   @computed('_rowValue.isCollapsed')
   get isCollapsed() {
@@ -95,6 +96,18 @@ export class TableRowMeta extends EmberObject {
     return parentMeta ? get(parentMeta, 'depth') + 1 : 0;
   }
 
+  @computed('_lastKnownIndex', '_prevSiblingMeta.index')
+  get index() {
+    let prevSiblingIndex = get(this, '_prevSiblingMeta.index');
+    let lastKnownIndex = get(this, '_lastKnownIndex');
+
+    if (lastKnownIndex === prevSiblingIndex) {
+      return lastKnownIndex + 1;
+    }
+
+    return lastKnownIndex;
+  }
+
   @computed('_tree.length')
   get first() {
     if (get(this, '_tree.length') === 0) {
@@ -112,18 +125,18 @@ export class TableRowMeta extends EmberObject {
   @computed('_tree.length')
   get next() {
     let tree = get(this, '_tree');
-    if (get(this, 'index') + 1 >= get(tree, 'length')) {
+    if (get(this, '_lastKnownIndex') + 1 >= get(tree, 'length')) {
       return null;
     }
-    return tree.objectAt(get(this, 'index') + 1);
+    return tree.objectAt(get(this, '_lastKnownIndex') + 1);
   }
 
   @computed('_tree.length')
   get prev() {
-    if (get(this, 'index') === 0) {
+    if (get(this, '_lastKnownIndex') === 0) {
       return null;
     }
-    return get(this, '_tree').objectAt(get(this, 'index') - 1);
+    return get(this, '_tree').objectAt(get(this, '_lastKnownIndex') - 1);
   }
 
   toggleCollapse() {
@@ -692,18 +705,28 @@ export default class CollapseTree extends EmberObject.extend(EmberArray) {
     @return {{ value: object, parents: Array<object> }}
   */
   objectAt(index) {
-    if (index >= get(this, 'length') || index < 0) {
+    let length = get(this, 'length');
+    if (index >= length || index < 0) {
       return undefined;
     }
 
+    let root = get(this, 'root');
+    let rowMetaCache = this.get('rowMetaCache');
+
     // We add a "fake" top level node to account for the root node
     let normalizedIndex = index + 1;
-    let result = get(this, 'root').objectAt(normalizedIndex);
-    let meta = this.get('rowMetaCache').get(result);
+    let result = root.objectAt(normalizedIndex);
+    let meta = rowMetaCache.get(result);
 
-    // Set the perceived index on the meta. It should be safe to do this here, since
-    // the row will always be retrieved via `objectAt` before being used.
-    set(meta, 'index', index);
+    // Set the last known index on the meta and link the next siblings meta
+    // so that its index can recompute in case it conflicts from shifting
+    set(meta, '_lastKnownIndex', index);
+
+    if (index < length - 1) {
+      let nextSibling = root.objectAt(normalizedIndex + 1);
+      let nextMeta = rowMetaCache.get(nextSibling);
+      set(nextMeta, '_prevSiblingMeta', meta);
+    }
 
     return result;
   }
diff --git a/tests/unit/-private/collapse-tree-test.js b/tests/unit/-private/collapse-tree-test.js
index 98ea7c493..e7c2d18a7 100644
--- a/tests/unit/-private/collapse-tree-test.js
+++ b/tests/unit/-private/collapse-tree-test.js
@@ -173,6 +173,25 @@ module('Unit | Private | CollapseTree', function(hooks) {
     }
   });
 
+  test('rowMeta index is recomputed when row is added or removed', function(assert) {
+    let rows = generateTree([1, [2, 3, [4, 5], 6], 7]);
+    tree = CollapseTree.create({ rows, rowMetaCache, enableTree: true });
+
+    let nodes = tree.toArray();
+    nodes.forEach((node, i) => assert.equal(metaFor(node).get('index'), i));
+
+    rows.unshiftObject({ value: 0 });
+
+    let firstNode = run(() => tree.objectAt(0));
+    nodes = [firstNode].concat(nodes);
+    nodes.forEach((node, i) => assert.equal(metaFor(node).get('index'), i));
+
+    rows.pushObject({ value: 8 });
+
+    let lastNode = run(() => tree.objectAt(8));
+    nodes.concat(lastNode).forEach((node, i) => assert.equal(metaFor(node).get('index'), i));
+  });
+
   test('can disable tree', function(assert) {
     tree = CollapseTree.create({
       rows: generateTree([0, [1, 2]]),