diff --git a/src/core/observer/scheduler.js b/src/core/observer/scheduler.js
index e7ccf57dd25..59c22aff7bf 100644
--- a/src/core/observer/scheduler.js
+++ b/src/core/observer/scheduler.js
@@ -98,7 +98,7 @@ function callUpdatedHooks (queue) {
   while (i--) {
     const watcher = queue[i]
     const vm = watcher.vm
-    if (vm._watcher === watcher && vm._isMounted) {
+    if (vm._watcher === watcher && vm._isMounted && !vm._isDestroyed) {
       callHook(vm, 'updated')
     }
   }
diff --git a/test/unit/features/options/lifecycle.spec.js b/test/unit/features/options/lifecycle.spec.js
index 3fa152e70c2..ccc9d2106de 100644
--- a/test/unit/features/options/lifecycle.spec.js
+++ b/test/unit/features/options/lifecycle.spec.js
@@ -199,6 +199,43 @@ describe('Options lifecycle hooks', () => {
         expect(calls).toEqual(['child', 'parent'])
       }).then(done)
     })
+
+    // #8076
+    it('should not be called after destroy', done => {
+      const updated = jasmine.createSpy('updated')
+      const destroyed = jasmine.createSpy('destroyed')
+
+      Vue.component('todo', {
+        template: '<div>{{todo.done}}</div>',
+        props: ['todo'],
+        destroyed,
+        updated
+      })
+
+      const vm = new Vue({
+        template: `
+          <div>
+            <todo v-for="t in pendingTodos" :todo="t" :key="t.id"></todo>
+          </div>
+        `,
+        data () {
+          return {
+            todos: [{ id: 1, done: false }]
+          }
+        },
+        computed: {
+          pendingTodos () {
+            return this.todos.filter(t => !t.done)
+          }
+        }
+      }).$mount()
+
+      vm.todos[0].done = true
+      waitForUpdate(() => {
+        expect(destroyed).toHaveBeenCalled()
+        expect(updated).not.toHaveBeenCalled()
+      }).then(done)
+    })
   })
 
   describe('beforeDestroy', () => {