diff --git a/flecs.c b/flecs.c
index f22aa1ac57..e74066ca48 100644
--- a/flecs.c
+++ b/flecs.c
@@ -469,6 +469,7 @@ struct ecs_table_t {
 
     int32_t refcount;                /* Increased when used as storage table */
     int32_t lock;                    /* Prevents modifications */
+    int32_t observed_count;          /* Number of observed entities in table */
     uint16_t record_count;           /* Table record count including wildcards */
 };
 
@@ -3237,6 +3238,8 @@ void fini_data(
     if (deactivate && count) {
         flecs_table_set_empty(world, table);
     }
+
+    table->observed_count = 0;
 }
 
 /* Cleanup, no OnRemove, don't update entity index, don't deactivate table */
@@ -4542,6 +4545,8 @@ void flecs_table_merge(
             flecs_table_set_empty(world, dst_table);
         }
         flecs_table_set_empty(world, src_table);
+        dst_table->observed_count += src_table->observed_count;
+        src_table->observed_count = 0;
     }
 
     check_table_sanity(src_table);
@@ -4791,6 +4796,12 @@ void ecs_table_swap_rows(
     flecs_table_swap(world, table, row_1, row_2);
 }
 
+int32_t flecs_table_observed_count(
+    const ecs_table_t *table)
+{
+    return table->observed_count;
+}
+
 
 static const char* mixin_kind_str[] = {
     [EcsMixinBase] = "base (should never be requested by application)",
@@ -6181,7 +6192,15 @@ void flecs_commit(
 {
     ecs_assert(!(world->flags & EcsWorldReadonly), ECS_INTERNAL_ERROR, NULL);
     
-    ecs_table_t *src_table = record ? record->table : NULL;
+    ecs_table_t *src_table = NULL;
+    uint32_t row_flags = 0;
+    bool observed = false;
+    if (record) {
+        src_table = record->table;
+        row_flags = record->row & ECS_ROW_FLAGS_MASK;
+        observed = row_flags & EcsEntityObservedAcyclic;
+    }
+
     if (src_table == dst_table) {
         /* If source and destination table are the same no action is needed *
          * However, if a component was added in the process of traversing a
@@ -6198,7 +6217,8 @@ void flecs_commit(
     }
 
     if (src_table) {
-        ecs_assert(dst_table != NULL, ECS_INTERNAL_ERROR, NULL);
+        ecs_assert(dst_table != NULL, ECS_INTERNAL_ERROR, NULL);  
+        dst_table->observed_count += observed;
 
         if (dst_table->type.count) { 
             move_entity(world, entity, record, dst_table, diff, 
@@ -6206,12 +6226,15 @@ void flecs_commit(
         } else {
             delete_entity(world, record, diff);
             record->table = NULL;
-        }      
+        }
+
+        src_table->observed_count -= observed;
     } else {        
+        dst_table->observed_count += observed;
         if (dst_table->type.count) {
-            record = new_entity(world, entity, record, dst_table, diff, 
+            new_entity(world, entity, record, dst_table, diff, 
                 construct, notify_on_set);
-        }        
+        }
     }
 
     /* If the entity is being watched, it is being monitored for changes and
@@ -6219,7 +6242,7 @@ void flecs_commit(
      * ensures that systems that rely on components from containers or prefabs
      * update the matched tables when the application adds or removes a 
      * component from, for example, a container. */
-    if (record->row & ECS_ROW_FLAGS_MASK) {
+    if (row_flags) {
         update_component_monitors(world, &diff->added, &diff->removed);
     }
 
@@ -6630,6 +6653,14 @@ void flecs_add_flag(
         ecs_record_t new_record = {.row = flag, .table = NULL};
         flecs_entities_set(world, entity, &new_record);
     } else {
+        if (flag == EcsEntityObservedAcyclic) {
+            if (!(record->row & flag)) {
+                ecs_table_t *table = record->table;
+                if (table) {
+                    table->observed_count ++;
+                }
+            }
+        }
         record->row |= flag;
     }
 }
@@ -7438,6 +7469,10 @@ void ecs_clear(
 
     ecs_table_t *table = r->table;
     if (table) {
+        if (r->row & EcsEntityObservedAcyclic) {
+            table->observed_count --;
+        }
+
         ecs_table_diff_t diff = {
             .removed = table->type,
             .un_set = { table->storage_ids, table->storage_count }
@@ -7914,7 +7949,14 @@ void ecs_delete(
     ecs_record_t *r = flecs_entities_get(world, entity);
     if (r) {
         ecs_flags32_t row_flags = ECS_RECORD_TO_ROW_FLAGS(r->row);
+        ecs_table_t *table;
         if (row_flags) {
+            if (row_flags & EcsEntityObservedAcyclic) {
+                table = r->table;
+                if (table) {
+                    table->observed_count --;
+                }
+            }
             if (row_flags & EcsEntityObservedId) {
                 flecs_on_delete(world, entity, 0);
                 flecs_on_delete(world, ecs_pair(entity, EcsWildcard), 0);
@@ -7929,7 +7971,7 @@ void ecs_delete(
             ecs_defer_begin(world);
         }
 
-        ecs_table_t *table = r->table;
+        table = r->table;
 
         /* If entity has components, remove them. Check if table is still alive,
          * as delete actions could have deleted the table already. */
@@ -37665,6 +37707,10 @@ void notify_subset(
             flecs_set_observers_notify(it, observable, ids, event,
                 ecs_pair(rel, EcsWildcard));
 
+            if (!table->observed_count) {
+                continue;
+            }
+
             ecs_entity_t *entities = ecs_storage_first(&table->data.entities);
             ecs_record_t **records = ecs_storage_first(&table->data.records);
 
@@ -37672,7 +37718,7 @@ void notify_subset(
                 uint32_t flags = ECS_RECORD_TO_ROW_FLAGS(records[e]->row);
                 if (flags & EcsEntityObservedAcyclic) {
                     /* Only notify for entities that are used in pairs with
-                    * acyclic relationships */
+                     * acyclic relationships */
                     notify_subset(world, it, observable, entities[e], event, ids);
                 }
             }
@@ -37730,14 +37776,17 @@ void flecs_emit(
     }
 
     if (count && !desc->table_event) {
+        if (!table->observed_count) {
+            return;
+        }
+
         ecs_record_t **recs = ecs_storage_get_t(
             &table->data.records, ecs_record_t*, row);
-
         for (i = 0; i < count; i ++) {
             ecs_record_t *r = recs[i];
             if (!r) {
                 /* If the event is emitted after a bulk operation, it's possible
-                 * that it hasn't been populate with entities yet. */
+                 * that it hasn't been populated with entities yet. */
                 continue;
             }
 
@@ -39705,16 +39754,18 @@ bool flecs_term_iter_next(
         if (!table) {
             if (!(tr = flecs_term_iter_next_table(iter))) {
                 if (iter->cur != iter->set_index && iter->set_index != NULL) {
-                    iter->cur = iter->set_index;
-                    if (iter->empty_tables) {
-                        flecs_table_cache_all_iter(
-                            &iter->set_index->cache, &iter->it);
-                    } else {
-                        flecs_table_cache_iter(
-                            &iter->set_index->cache, &iter->it);
+                    if (iter->observed_table_count != 0) {
+                        iter->cur = iter->set_index;
+                        if (iter->empty_tables) {
+                            flecs_table_cache_all_iter(
+                                &iter->set_index->cache, &iter->it);
+                        } else {
+                            flecs_table_cache_iter(
+                                &iter->set_index->cache, &iter->it);
+                        }
+                        iter->index = 0;
+                        tr = flecs_term_iter_next_table(iter);
                     }
-                    iter->index = 0;
-                    tr = flecs_term_iter_next_table(iter);
                 }
 
                 if (!tr) {
@@ -39723,6 +39774,9 @@ bool flecs_term_iter_next(
             }
 
             table = tr->hdr.table;
+            if (table->observed_count) {
+                iter->observed_table_count ++;
+            }
 
             if (!match_prefab && (table->flags & EcsTableIsPrefab)) {
                 continue;
diff --git a/flecs.h b/flecs.h
index 8fe7a54eb3..62e28cc9c0 100644
--- a/flecs.h
+++ b/flecs.h
@@ -2709,6 +2709,7 @@ typedef struct ecs_term_iter_t {
     ecs_id_record_t *cur;
     ecs_table_cache_iter_t it;
     int32_t index;
+    int32_t observed_table_count;
     
     ecs_table_t *table;
     int32_t cur_match;
@@ -2961,6 +2962,10 @@ char* ecs_asprintf(
     const char *fmt,
     ...);
 
+FLECS_DBG_API
+int32_t flecs_table_observed_count(
+    const ecs_table_t *table);
+
 /** Calculate offset from address */
 #ifdef __cplusplus
 #define ECS_OFFSET(o, offset) reinterpret_cast<void*>((reinterpret_cast<uintptr_t>(o)) + (static_cast<uintptr_t>(offset)))
diff --git a/include/flecs/private/api_support.h b/include/flecs/private/api_support.h
index a09a1ca683..3f886c524b 100644
--- a/include/flecs/private/api_support.h
+++ b/include/flecs/private/api_support.h
@@ -63,6 +63,10 @@ char* ecs_asprintf(
     const char *fmt,
     ...);
 
+FLECS_DBG_API
+int32_t flecs_table_observed_count(
+    const ecs_table_t *table);
+
 /** Calculate offset from address */
 #ifdef __cplusplus
 #define ECS_OFFSET(o, offset) reinterpret_cast<void*>((reinterpret_cast<uintptr_t>(o)) + (static_cast<uintptr_t>(offset)))
diff --git a/include/flecs/private/api_types.h b/include/flecs/private/api_types.h
index 44dacf7791..30d2053135 100644
--- a/include/flecs/private/api_types.h
+++ b/include/flecs/private/api_types.h
@@ -117,6 +117,7 @@ typedef struct ecs_term_iter_t {
     ecs_id_record_t *cur;
     ecs_table_cache_iter_t it;
     int32_t index;
+    int32_t observed_table_count;
     
     ecs_table_t *table;
     int32_t cur_match;
diff --git a/src/entity.c b/src/entity.c
index 9046cd237e..3238c3ba14 100644
--- a/src/entity.c
+++ b/src/entity.c
@@ -965,7 +965,15 @@ void flecs_commit(
 {
     ecs_assert(!(world->flags & EcsWorldReadonly), ECS_INTERNAL_ERROR, NULL);
     
-    ecs_table_t *src_table = record ? record->table : NULL;
+    ecs_table_t *src_table = NULL;
+    uint32_t row_flags = 0;
+    bool observed = false;
+    if (record) {
+        src_table = record->table;
+        row_flags = record->row & ECS_ROW_FLAGS_MASK;
+        observed = row_flags & EcsEntityObservedAcyclic;
+    }
+
     if (src_table == dst_table) {
         /* If source and destination table are the same no action is needed *
          * However, if a component was added in the process of traversing a
@@ -982,7 +990,8 @@ void flecs_commit(
     }
 
     if (src_table) {
-        ecs_assert(dst_table != NULL, ECS_INTERNAL_ERROR, NULL);
+        ecs_assert(dst_table != NULL, ECS_INTERNAL_ERROR, NULL);  
+        dst_table->observed_count += observed;
 
         if (dst_table->type.count) { 
             move_entity(world, entity, record, dst_table, diff, 
@@ -990,12 +999,15 @@ void flecs_commit(
         } else {
             delete_entity(world, record, diff);
             record->table = NULL;
-        }      
+        }
+
+        src_table->observed_count -= observed;
     } else {        
+        dst_table->observed_count += observed;
         if (dst_table->type.count) {
-            record = new_entity(world, entity, record, dst_table, diff, 
+            new_entity(world, entity, record, dst_table, diff, 
                 construct, notify_on_set);
-        }        
+        }
     }
 
     /* If the entity is being watched, it is being monitored for changes and
@@ -1003,7 +1015,7 @@ void flecs_commit(
      * ensures that systems that rely on components from containers or prefabs
      * update the matched tables when the application adds or removes a 
      * component from, for example, a container. */
-    if (record->row & ECS_ROW_FLAGS_MASK) {
+    if (row_flags) {
         update_component_monitors(world, &diff->added, &diff->removed);
     }
 
@@ -1414,6 +1426,14 @@ void flecs_add_flag(
         ecs_record_t new_record = {.row = flag, .table = NULL};
         flecs_entities_set(world, entity, &new_record);
     } else {
+        if (flag == EcsEntityObservedAcyclic) {
+            if (!(record->row & flag)) {
+                ecs_table_t *table = record->table;
+                if (table) {
+                    table->observed_count ++;
+                }
+            }
+        }
         record->row |= flag;
     }
 }
@@ -2222,6 +2242,10 @@ void ecs_clear(
 
     ecs_table_t *table = r->table;
     if (table) {
+        if (r->row & EcsEntityObservedAcyclic) {
+            table->observed_count --;
+        }
+
         ecs_table_diff_t diff = {
             .removed = table->type,
             .un_set = { table->storage_ids, table->storage_count }
@@ -2698,7 +2722,14 @@ void ecs_delete(
     ecs_record_t *r = flecs_entities_get(world, entity);
     if (r) {
         ecs_flags32_t row_flags = ECS_RECORD_TO_ROW_FLAGS(r->row);
+        ecs_table_t *table;
         if (row_flags) {
+            if (row_flags & EcsEntityObservedAcyclic) {
+                table = r->table;
+                if (table) {
+                    table->observed_count --;
+                }
+            }
             if (row_flags & EcsEntityObservedId) {
                 flecs_on_delete(world, entity, 0);
                 flecs_on_delete(world, ecs_pair(entity, EcsWildcard), 0);
@@ -2713,7 +2744,7 @@ void ecs_delete(
             ecs_defer_begin(world);
         }
 
-        ecs_table_t *table = r->table;
+        table = r->table;
 
         /* If entity has components, remove them. Check if table is still alive,
          * as delete actions could have deleted the table already. */
diff --git a/src/filter.c b/src/filter.c
index 495a3cb31f..7ac41c8c0c 100644
--- a/src/filter.c
+++ b/src/filter.c
@@ -1943,16 +1943,18 @@ bool flecs_term_iter_next(
         if (!table) {
             if (!(tr = flecs_term_iter_next_table(iter))) {
                 if (iter->cur != iter->set_index && iter->set_index != NULL) {
-                    iter->cur = iter->set_index;
-                    if (iter->empty_tables) {
-                        flecs_table_cache_all_iter(
-                            &iter->set_index->cache, &iter->it);
-                    } else {
-                        flecs_table_cache_iter(
-                            &iter->set_index->cache, &iter->it);
+                    if (iter->observed_table_count != 0) {
+                        iter->cur = iter->set_index;
+                        if (iter->empty_tables) {
+                            flecs_table_cache_all_iter(
+                                &iter->set_index->cache, &iter->it);
+                        } else {
+                            flecs_table_cache_iter(
+                                &iter->set_index->cache, &iter->it);
+                        }
+                        iter->index = 0;
+                        tr = flecs_term_iter_next_table(iter);
                     }
-                    iter->index = 0;
-                    tr = flecs_term_iter_next_table(iter);
                 }
 
                 if (!tr) {
@@ -1961,6 +1963,9 @@ bool flecs_term_iter_next(
             }
 
             table = tr->hdr.table;
+            if (table->observed_count) {
+                iter->observed_table_count ++;
+            }
 
             if (!match_prefab && (table->flags & EcsTableIsPrefab)) {
                 continue;
diff --git a/src/observable.c b/src/observable.c
index f6b3a82df1..c8d6f04cc3 100644
--- a/src/observable.c
+++ b/src/observable.c
@@ -69,6 +69,10 @@ void notify_subset(
             flecs_set_observers_notify(it, observable, ids, event,
                 ecs_pair(rel, EcsWildcard));
 
+            if (!table->observed_count) {
+                continue;
+            }
+
             ecs_entity_t *entities = ecs_storage_first(&table->data.entities);
             ecs_record_t **records = ecs_storage_first(&table->data.records);
 
@@ -76,7 +80,7 @@ void notify_subset(
                 uint32_t flags = ECS_RECORD_TO_ROW_FLAGS(records[e]->row);
                 if (flags & EcsEntityObservedAcyclic) {
                     /* Only notify for entities that are used in pairs with
-                    * acyclic relationships */
+                     * acyclic relationships */
                     notify_subset(world, it, observable, entities[e], event, ids);
                 }
             }
@@ -134,14 +138,17 @@ void flecs_emit(
     }
 
     if (count && !desc->table_event) {
+        if (!table->observed_count) {
+            return;
+        }
+
         ecs_record_t **recs = ecs_storage_get_t(
             &table->data.records, ecs_record_t*, row);
-
         for (i = 0; i < count; i ++) {
             ecs_record_t *r = recs[i];
             if (!r) {
                 /* If the event is emitted after a bulk operation, it's possible
-                 * that it hasn't been populate with entities yet. */
+                 * that it hasn't been populated with entities yet. */
                 continue;
             }
 
diff --git a/src/private_types.h b/src/private_types.h
index 75cc4ad619..21b3b1e37e 100644
--- a/src/private_types.h
+++ b/src/private_types.h
@@ -189,6 +189,7 @@ struct ecs_table_t {
 
     int32_t refcount;                /* Increased when used as storage table */
     int32_t lock;                    /* Prevents modifications */
+    int32_t observed_count;          /* Number of observed entities in table */
     uint16_t record_count;           /* Table record count including wildcards */
 };
 
diff --git a/src/table.c b/src/table.c
index c5f98c0eeb..3bf3a9b6b9 100644
--- a/src/table.c
+++ b/src/table.c
@@ -961,6 +961,8 @@ void fini_data(
     if (deactivate && count) {
         flecs_table_set_empty(world, table);
     }
+
+    table->observed_count = 0;
 }
 
 /* Cleanup, no OnRemove, don't update entity index, don't deactivate table */
@@ -2266,6 +2268,8 @@ void flecs_table_merge(
             flecs_table_set_empty(world, dst_table);
         }
         flecs_table_set_empty(world, src_table);
+        dst_table->observed_count += src_table->observed_count;
+        src_table->observed_count = 0;
     }
 
     check_table_sanity(src_table);
@@ -2514,3 +2518,9 @@ void ecs_table_swap_rows(
 {
     flecs_table_swap(world, table, row_1, row_2);
 }
+
+int32_t flecs_table_observed_count(
+    const ecs_table_t *table)
+{
+    return table->observed_count;
+}
diff --git a/test/api/project.json b/test/api/project.json
index a8c4963287..085406ce31 100644
--- a/test/api/project.json
+++ b/test/api/project.json
@@ -2236,7 +2236,13 @@
                 "create_65k_tables",
                 "no_duplicate_root_table_id",
                 "override_os_api_w_addon",
-                "records_resize_on_override"
+                "records_resize_on_override",
+                "table_observed_after_add",
+                "table_observed_after_remove",
+                "table_observed_after_clear",
+                "table_observed_after_delete",
+                "table_observed_after_on_remove",
+                "table_observed_after_entity_flag"
             ]
         }, {
             "id": "Error",
diff --git a/test/api/src/Internals.c b/test/api/src/Internals.c
index b84d8fb54d..657782166e 100644
--- a/test/api/src/Internals.c
+++ b/test/api/src/Internals.c
@@ -318,3 +318,177 @@ void Internals_records_resize_on_override() {
 
     ecs_fini(world);
 }
+
+void Internals_table_observed_after_add() {
+    ecs_world_t *world = ecs_mini();
+
+    ECS_TAG(world, TagA);
+    ECS_TAG(world, TagB);
+
+    ecs_entity_t p = ecs_new_id(world);
+    ecs_entity_t c = ecs_new_w_pair(world, EcsChildOf, p);
+    ecs_table_t *pt = ecs_get_table(world, p);
+    ecs_table_t *ct = ecs_get_table(world, c);
+    test_assert(pt == NULL);
+    test_assert(ct != NULL);
+    test_int(flecs_table_observed_count(ct), 0);
+
+    ecs_add(world, p, TagA);
+    ecs_table_t *pt_a = ecs_get_table(world, p);
+    test_assert(pt_a != NULL);
+    test_int(flecs_table_observed_count(pt_a), 1);
+
+    ecs_add(world, p, TagB);
+    ecs_table_t *pt_b = ecs_get_table(world, p);
+    test_assert(pt_b != NULL);
+    test_int(flecs_table_observed_count(pt_a), 0);
+    test_int(flecs_table_observed_count(pt_b), 1);
+
+    ecs_fini(world);
+}
+
+void Internals_table_observed_after_remove() {
+    ecs_world_t *world = ecs_mini();
+
+    ECS_TAG(world, TagA);
+    ECS_TAG(world, TagB);
+
+    ecs_entity_t p = ecs_new_id(world);
+    ecs_entity_t c = ecs_new_w_pair(world, EcsChildOf, p);
+    ecs_table_t *pt = ecs_get_table(world, p);
+    ecs_table_t *ct = ecs_get_table(world, c);
+    test_assert(pt == NULL);
+    test_assert(ct != NULL);
+    test_int(flecs_table_observed_count(ct), 0);
+
+    ecs_add(world, p, TagA);
+    ecs_table_t *pt_a = ecs_get_table(world, p);
+    test_assert(pt_a != NULL);
+    test_int(flecs_table_observed_count(pt_a), 1);
+
+    ecs_add(world, p, TagB);
+    ecs_table_t *pt_b = ecs_get_table(world, p);
+    test_assert(pt_b != NULL);
+    test_int(flecs_table_observed_count(pt_a), 0);
+    test_int(flecs_table_observed_count(pt_b), 1);
+
+    ecs_remove(world, p, TagB);
+    test_int(flecs_table_observed_count(pt_a), 1);
+    test_int(flecs_table_observed_count(pt_b), 0);
+
+    ecs_remove(world, p, TagA);
+    test_int(flecs_table_observed_count(pt_a), 0);
+    test_int(flecs_table_observed_count(pt_b), 0);
+
+    ecs_fini(world);
+}
+
+void Internals_table_observed_after_clear() {
+    ecs_world_t *world = ecs_mini();
+
+    ECS_TAG(world, TagA);
+
+    ecs_entity_t p = ecs_new_id(world);
+    ecs_entity_t c = ecs_new_w_pair(world, EcsChildOf, p);
+    ecs_table_t *pt = ecs_get_table(world, p);
+    ecs_table_t *ct = ecs_get_table(world, c);
+    test_assert(pt == NULL);
+    test_assert(ct != NULL);
+    test_int(flecs_table_observed_count(ct), 0);
+
+    ecs_add(world, p, TagA);
+    ecs_table_t *pt_a = ecs_get_table(world, p);
+    test_assert(pt_a != NULL);
+    test_int(flecs_table_observed_count(pt_a), 1);
+
+    ecs_clear(world, p);
+    test_int(flecs_table_observed_count(pt_a), 0);
+
+    ecs_add(world, p, TagA);
+    test_int(flecs_table_observed_count(pt_a), 1);
+
+    ecs_fini(world);
+}
+
+void Internals_table_observed_after_delete() {
+    ecs_world_t *world = ecs_mini();
+
+    ECS_TAG(world, TagA);
+
+    ecs_entity_t p = ecs_new_id(world);
+    ecs_entity_t c = ecs_new_w_pair(world, EcsChildOf, p);
+    ecs_table_t *pt = ecs_get_table(world, p);
+    ecs_table_t *ct = ecs_get_table(world, c);
+    test_assert(pt == NULL);
+    test_assert(ct != NULL);
+    test_int(flecs_table_observed_count(ct), 0);
+
+    ecs_add(world, p, TagA);
+    ecs_table_t *pt_a = ecs_get_table(world, p);
+    test_assert(pt_a != NULL);
+    test_int(flecs_table_observed_count(pt_a), 1);
+
+    ecs_delete(world, p);
+    test_int(flecs_table_observed_count(pt_a), 0);
+
+    ecs_fini(world);
+}
+
+void Internals_table_observed_after_on_remove() {
+    ecs_world_t *world = ecs_mini();
+
+    ECS_TAG(world, TagA);
+
+    ecs_entity_t p = ecs_new_id(world);
+    ecs_entity_t c = ecs_new_w_pair(world, EcsChildOf, p);
+    ecs_table_t *pt = ecs_get_table(world, p);
+    ecs_table_t *ct = ecs_get_table(world, c);
+    test_assert(pt == NULL);
+    test_assert(ct != NULL);
+    test_int(flecs_table_observed_count(ct), 0);
+
+    ecs_entity_t t = ecs_new_id(world);
+    ecs_add_id(world, p, t);
+    ecs_table_t *pt_t = ecs_get_table(world, p);
+    test_assert(pt_t != NULL);
+    test_int(flecs_table_observed_count(pt_t), 1);
+
+    ecs_add(world, p, TagA);
+    ecs_table_t *pt_ta = ecs_get_table(world, p);
+    test_assert(pt_ta != NULL);
+    test_int(flecs_table_observed_count(pt_t), 0);
+    test_int(flecs_table_observed_count(pt_ta), 1);
+
+    ecs_delete(world, t);
+    test_assert(!ecs_has_id(world, p, t));
+    test_assert(ecs_has(world, p, TagA));
+
+    ecs_table_t *p_a = ecs_get_table(world, p);
+    test_assert(p_a != NULL);
+    test_int(flecs_table_observed_count(p_a), 1);
+
+    ecs_fini(world);
+}
+
+void Internals_table_observed_after_entity_flag() {
+    ecs_world_t *world = ecs_mini();
+
+    ECS_TAG(world, TagA);
+    ECS_TAG(world, TagB);
+
+    ecs_entity_t p = ecs_new_id(world);
+
+    ecs_add(world, p, TagA);
+    ecs_table_t *p_a = ecs_get_table(world, p);
+    test_assert(p_a != NULL);
+    test_int(flecs_table_observed_count(p_a), 0);
+
+    ecs_entity_t c = ecs_new_w_pair(world, EcsChildOf, p);
+    ecs_table_t *ct = ecs_get_table(world, c);
+    test_assert(ct != NULL);
+    test_int(flecs_table_observed_count(ct), 0);
+    test_int(flecs_table_observed_count(p_a), 1);
+
+    ecs_fini(world);
+
+}
diff --git a/test/api/src/main.c b/test/api/src/main.c
index c2d82b2181..4e8e728ad0 100644
--- a/test/api/src/main.c
+++ b/test/api/src/main.c
@@ -2140,6 +2140,12 @@ void Internals_create_65k_tables(void);
 void Internals_no_duplicate_root_table_id(void);
 void Internals_override_os_api_w_addon(void);
 void Internals_records_resize_on_override(void);
+void Internals_table_observed_after_add(void);
+void Internals_table_observed_after_remove(void);
+void Internals_table_observed_after_clear(void);
+void Internals_table_observed_after_delete(void);
+void Internals_table_observed_after_on_remove(void);
+void Internals_table_observed_after_entity_flag(void);
 
 // Testsuite 'Error'
 void Error_setup(void);
@@ -10394,6 +10400,30 @@ bake_test_case Internals_testcases[] = {
     {
         "records_resize_on_override",
         Internals_records_resize_on_override
+    },
+    {
+        "table_observed_after_add",
+        Internals_table_observed_after_add
+    },
+    {
+        "table_observed_after_remove",
+        Internals_table_observed_after_remove
+    },
+    {
+        "table_observed_after_clear",
+        Internals_table_observed_after_clear
+    },
+    {
+        "table_observed_after_delete",
+        Internals_table_observed_after_delete
+    },
+    {
+        "table_observed_after_on_remove",
+        Internals_table_observed_after_on_remove
+    },
+    {
+        "table_observed_after_entity_flag",
+        Internals_table_observed_after_entity_flag
     }
 };
 
@@ -10775,7 +10805,7 @@ static bake_test_suite suites[] = {
         "Internals",
         Internals_setup,
         NULL,
-        11,
+        17,
         Internals_testcases
     },
     {