diff --git a/.changeset/deep-crews-open.md b/.changeset/deep-crews-open.md
new file mode 100644
index 0000000000..b46a786d5a
--- /dev/null
+++ b/.changeset/deep-crews-open.md
@@ -0,0 +1,5 @@
+---
+'@tanstack/angular-query-experimental': minor
+---
+
+require Angular v19+ and use Angular component effect scheduling
diff --git a/docs/framework/angular/angular-httpclient-and-other-data-fetching-clients.md b/docs/framework/angular/angular-httpclient-and-other-data-fetching-clients.md
index 0784526cb5..7bd3764e0e 100644
--- a/docs/framework/angular/angular-httpclient-and-other-data-fetching-clients.md
+++ b/docs/framework/angular/angular-httpclient-and-other-data-fetching-clients.md
@@ -36,8 +36,6 @@ class ExampleComponent {
 ```
 
 > Since Angular is moving towards RxJS as an optional dependency, it's expected that `HttpClient` will also support promises in the future.
->
-> Support for observables in TanStack Query for Angular is planned.
 
 ## Comparison table
 
diff --git a/docs/framework/angular/guides/caching.md b/docs/framework/angular/guides/caching.md
index 32c6e6d58d..5de89421a5 100644
--- a/docs/framework/angular/guides/caching.md
+++ b/docs/framework/angular/guides/caching.md
@@ -27,7 +27,7 @@ Let's assume we are using the default `gcTime` of **5 minutes** and the default
   - When the request completes successfully, the cache's data under the `['todos']` key is updated with the new data, and both instances are updated with the new data.
 - Both instances of the `injectQuery(() => ({ queryKey: ['todos'], queryFn: fetchTodos })` query are destroyed and no longer in use.
   - Since there are no more active instances of this query, a garbage collection timeout is set using `gcTime` to delete and garbage collect the query (defaults to **5 minutes**).
-- Before the cache timeout has completed, another instance of `injectQuery(() => ({ queryKey: ['todos'], queyFn: fetchTodos })` mounts. The query immediately returns the available cached data while the `fetchTodos` function is being run in the background. When it completes successfully, it will populate the cache with fresh data.
+- Before the cache timeout has completed, another instance of `injectQuery(() => ({ queryKey: ['todos'], queryFn: fetchTodos })` mounts. The query immediately returns the available cached data while the `fetchTodos` function is being run in the background. When it completes successfully, it will populate the cache with fresh data.
 - The final instance of `injectQuery(() => ({ queryKey: ['todos'], queryFn: fetchTodos })` gets destroyed.
 - No more instances of `injectQuery(() => ({ queryKey: ['todos'], queryFn: fetchTodos })` appear within **5 minutes**.
   - The cached data under the `['todos']` key is deleted and garbage collected.
diff --git a/docs/framework/angular/guides/default-query-function.md b/docs/framework/angular/guides/default-query-function.md
index 75e0fa3c48..4db44c9828 100644
--- a/docs/framework/angular/guides/default-query-function.md
+++ b/docs/framework/angular/guides/default-query-function.md
@@ -28,7 +28,10 @@ bootstrapApplication(MyAppComponent, {
   providers: [provideTanStackQuery(queryClient)],
 })
 
-export class PostsComponent {
+@Component({
+  // ...
+})
+class PostsComponent {
   // All you have to do now is pass a key!
   postsQuery = injectQuery<Array<Post>>(() => ({
     queryKey: ['/posts'],
@@ -36,11 +39,16 @@ export class PostsComponent {
   // ...
 }
 
-export class PostComponent {
+@Component({
+  // ...
+})
+class PostComponent {
+  postId = input(0)
+
   // You can even leave out the queryFn and just go straight into options
   postQuery = injectQuery<Post>(() => ({
-    enabled: this.postIdSignal() > 0,
-    queryKey: [`/posts/${this.postIdSignal()}`],
+    enabled: this.postId() > 0,
+    queryKey: [`/posts/${this.postId()}`],
   }))
   // ...
 }
diff --git a/docs/framework/angular/guides/dependent-queries.md b/docs/framework/angular/guides/dependent-queries.md
index 38afbd491f..8fc8123cec 100644
--- a/docs/framework/angular/guides/dependent-queries.md
+++ b/docs/framework/angular/guides/dependent-queries.md
@@ -10,14 +10,14 @@ replace: { 'useQuery': 'injectQuery', 'useQueries': 'injectQueries' }
 ```ts
 // Get the user
 userQuery = injectQuery(() => ({
-  queryKey: ['user', email],
-  queryFn: getUserByEmail,
+  queryKey: ['user', this.email()],
+  queryFn: this.getUserByEmail,
 }))
 
 // Then get the user's projects
 projectsQuery = injectQuery(() => ({
   queryKey: ['projects', this.userQuery.data()?.id],
-  queryFn: getProjectsByUser,
+  queryFn: this.getProjectsByUser,
   // The query will not execute until the user id exists
   enabled: !!this.userQuery.data()?.id,
 }))
@@ -26,8 +26,23 @@ projectsQuery = injectQuery(() => ({
 [//]: # 'Example'
 [//]: # 'Example2'
 
+Dynamic parallel query - `injectQueries` can depend on a previous query also, here's how to achieve this:
+
 ```ts
-// injectQueries is under development for Angular Query
+// Get the users ids
+userIds = injectQuery(() => ({
+  queryKey: ['users'],
+  queryFn: getUserData,
+  select: (users) => users.map((user) => user.id),
+}))
+
+// Then get the users messages
+userQueries = injectQueries(() => ({
+  queries: (this.userIds() ?? []).map((userId) => ({
+    queryKey: ['user', userId],
+    queryFn: () => getUserById(userId),
+  })),
+}))
 ```
 
 [//]: # 'Example2'
diff --git a/docs/framework/angular/guides/disabling-queries.md b/docs/framework/angular/guides/disabling-queries.md
index 35da0225de..2977491196 100644
--- a/docs/framework/angular/guides/disabling-queries.md
+++ b/docs/framework/angular/guides/disabling-queries.md
@@ -13,9 +13,9 @@ replace: { 'useQuery': 'injectQuery' }
   template: `<div>
     <button (click)="query.refetch()">Fetch Todos</button>
 
-    @if (query.data()) {
+    @if (query.data(); as data) {
       <ul>
-        @for (todo of query.data(); track todo.id) {
+        @for (todo of data; track todo.id) {
           <li>{{ todo.title }}</li>
         }
       </ul>
@@ -70,7 +70,7 @@ export class TodosComponent {
 [//]: # 'Example3'
 
 ```angular-ts
-import { skipToken, injectQuery } from '@tanstack/query-angular'
+import { skipToken, injectQuery } from '@tanstack/angular-query-experimental'
 
 @Component({
   selector: 'todos',
diff --git a/docs/framework/angular/guides/does-this-replace-client-state.md b/docs/framework/angular/guides/does-this-replace-client-state.md
index 3872115c94..0c16fb3568 100644
--- a/docs/framework/angular/guides/does-this-replace-client-state.md
+++ b/docs/framework/angular/guides/does-this-replace-client-state.md
@@ -7,5 +7,7 @@ replace:
     'useQuery': 'injectQuery',
     'useMutation': 'injectMutation',
     'hook': 'function',
+    'Redux, MobX or': 'NgRx Store or',
+    'Redux, MobX, Zustand': 'NgRx Store, custom services with RxJS',
   }
 ---
diff --git a/docs/framework/angular/guides/important-defaults.md b/docs/framework/angular/guides/important-defaults.md
index 886792038b..b8af966642 100644
--- a/docs/framework/angular/guides/important-defaults.md
+++ b/docs/framework/angular/guides/important-defaults.md
@@ -4,7 +4,6 @@ title: Important Defaults
 ref: docs/framework/react/guides/important-defaults.md
 replace:
   {
-    'React': 'Angular',
     'react-query': 'angular-query',
     'useQuery': 'injectQuery',
     'useInfiniteQuery': 'injectInfiniteQuery',
diff --git a/docs/framework/angular/guides/infinite-queries.md b/docs/framework/angular/guides/infinite-queries.md
index 9fdde83e26..35371a5ff4 100644
--- a/docs/framework/angular/guides/infinite-queries.md
+++ b/docs/framework/angular/guides/infinite-queries.md
@@ -75,6 +75,8 @@ export class Example {
   template: ` <list-component (endReached)="fetchNextPage()" /> `,
 })
 export class Example {
+  projectsService = inject(ProjectsService)
+
   query = injectInfiniteQuery(() => ({
     queryKey: ['projects'],
     queryFn: async ({ pageParam }) => {
diff --git a/docs/framework/angular/guides/initial-query-data.md b/docs/framework/angular/guides/initial-query-data.md
index 28673844be..7cd6472c4f 100644
--- a/docs/framework/angular/guides/initial-query-data.md
+++ b/docs/framework/angular/guides/initial-query-data.md
@@ -81,7 +81,7 @@ result = injectQuery(() => ({
 ```ts
 result = injectQuery(() => ({
   queryKey: ['todo', this.todoId()],
-  queryFn: () => fetch('/todos'),
+  queryFn: () => fetch(`/todos/${this.todoId()}`),
   initialData: () => {
     // Use a todo from the 'todos' query as the initial data for this todo query
     return this.queryClient
@@ -99,9 +99,11 @@ result = injectQuery(() => ({
   queryKey: ['todos', this.todoId()],
   queryFn: () => fetch(`/todos/${this.todoId()}`),
   initialData: () =>
-    queryClient.getQueryData(['todos'])?.find((d) => d.id === this.todoId()),
+    this.queryClient
+      .getQueryData(['todos'])
+      ?.find((d) => d.id === this.todoId()),
   initialDataUpdatedAt: () =>
-    queryClient.getQueryState(['todos'])?.dataUpdatedAt,
+    this.queryClient.getQueryState(['todos'])?.dataUpdatedAt,
 }))
 ```
 
@@ -114,7 +116,7 @@ result = injectQuery(() => ({
   queryFn: () => fetch(`/todos/${this.todoId()}`),
   initialData: () => {
     // Get the query state
-    const state = queryClient.getQueryState(['todos'])
+    const state = this.queryClient.getQueryState(['todos'])
 
     // If the query exists and has data that is no older than 10 seconds...
     if (state && Date.now() - state.dataUpdatedAt <= 10 * 1000) {
diff --git a/docs/framework/angular/guides/invalidations-from-mutations.md b/docs/framework/angular/guides/invalidations-from-mutations.md
index 18f84e9ec3..74245f212b 100644
--- a/docs/framework/angular/guides/invalidations-from-mutations.md
+++ b/docs/framework/angular/guides/invalidations-from-mutations.md
@@ -2,7 +2,12 @@
 id: invalidations-from-mutations
 title: Invalidations from Mutations
 ref: docs/framework/react/guides/invalidations-from-mutations.md
-replace: { 'useMutation': 'injectMutation', 'hook': 'function' }
+replace:
+  {
+    'react-query': 'angular-query-experimental',
+    'useMutation': 'injectMutation',
+    'hook': 'function',
+  }
 ---
 
 [//]: # 'Example'
@@ -17,11 +22,15 @@ mutation = injectMutation(() => ({
 [//]: # 'Example2'
 
 ```ts
+import { Component, inject } from '@angular/core'
 import {
   injectMutation,
   QueryClient,
 } from '@tanstack/angular-query-experimental'
 
+@Component({
+  // ...
+})
 export class TodosComponent {
   queryClient = inject(QueryClient)
 
diff --git a/docs/framework/angular/guides/mutations.md b/docs/framework/angular/guides/mutations.md
index f511808231..b769ad8ee1 100644
--- a/docs/framework/angular/guides/mutations.md
+++ b/docs/framework/angular/guides/mutations.md
@@ -243,12 +243,15 @@ queryClient.setMutationDefaults(['addTodo'], {
   retry: 3,
 })
 
-class someComponent {
+@Component({
+  // ...
+})
+class SomeComponent {
   // Start mutation in some component:
   mutation = injectMutation(() => ({ mutationKey: ['addTodo'] }))
 
   someMethod() {
-    mutation.mutate({ title: 'title' })
+    this.mutation.mutate({ title: 'title' })
   }
 }
 
diff --git a/docs/framework/angular/guides/paginated-queries.md b/docs/framework/angular/guides/paginated-queries.md
index 4baa3d4cfb..d8a5900995 100644
--- a/docs/framework/angular/guides/paginated-queries.md
+++ b/docs/framework/angular/guides/paginated-queries.md
@@ -35,9 +35,9 @@ const result = injectQuery(() => ({
         instantaneously while they are also re-fetched invisibly in the
         background.
       </p>
-      @if (query.status() === 'pending') {
+      @if (query.isPending()) {
         <div>Loading...</div>
-      } @else if (query.status() === 'error') {
+      } @else if (query.isError()) {
         <div>Error: {{ query.error().message }}</div>
       } @else {
         <!-- 'data' will either resolve to the latest page's data -->
@@ -83,7 +83,7 @@ export class PaginationExampleComponent {
     effect(() => {
       // Prefetch the next page!
       if (!this.query.isPlaceholderData() && this.query.data()?.hasMore) {
-        this.#queryClient.prefetchQuery({
+        this.queryClient.prefetchQuery({
           queryKey: ['projects', this.page() + 1],
           queryFn: () => lastValueFrom(fetchProjects(this.page() + 1)),
         })
diff --git a/docs/framework/angular/guides/parallel-queries.md b/docs/framework/angular/guides/parallel-queries.md
index f88756a2a8..a7e7c9b6e4 100644
--- a/docs/framework/angular/guides/parallel-queries.md
+++ b/docs/framework/angular/guides/parallel-queries.md
@@ -17,6 +17,9 @@ replace:
 [//]: # 'Example'
 
 ```ts
+@Component({
+  // ...
+})
 export class AppComponent {
   // The following queries will execute in parallel
   usersQuery = injectQuery(() => ({ queryKey: ['users'], queryFn: fetchUsers }))
@@ -39,12 +42,14 @@ TanStack Query provides `injectQueries`, which you can use to dynamically execut
 [//]: # 'Example2'
 
 ```ts
+@Component({
+  // ...
+})
 export class AppComponent {
   users = signal<Array<User>>([])
 
-  // Please note injectQueries is under development and this code does not work yet
   userQueries = injectQueries(() => ({
-    queries: users().map((user) => {
+    queries: this.users().map((user) => {
       return {
         queryKey: ['user', user.id],
         queryFn: () => fetchUserById(user.id),
diff --git a/docs/framework/angular/guides/placeholder-query-data.md b/docs/framework/angular/guides/placeholder-query-data.md
index ba92fbc4ed..2298d7bd2c 100644
--- a/docs/framework/angular/guides/placeholder-query-data.md
+++ b/docs/framework/angular/guides/placeholder-query-data.md
@@ -7,6 +7,9 @@ ref: docs/framework/react/guides/placeholder-query-data.md
 [//]: # 'ExampleValue'
 
 ```ts
+@Component({
+  // ...
+})
 class TodosComponent {
   result = injectQuery(() => ({
     queryKey: ['todos'],
@@ -22,10 +25,15 @@ class TodosComponent {
 [//]: # 'ExampleFunction'
 
 ```ts
-class TodosComponent {
+@Component({
+  // ...
+})
+export class TodosComponent {
+  todoId = signal(1)
+
   result = injectQuery(() => ({
-    queryKey: ['todos', id()],
-    queryFn: () => fetch(`/todos/${id}`),
+    queryKey: ['todos', this.todoId()],
+    queryFn: () => fetch(`/todos/${this.todoId()}`),
     placeholderData: (previousData, previousQuery) => previousData,
   }))
 }
@@ -35,6 +43,9 @@ class TodosComponent {
 [//]: # 'ExampleCache'
 
 ```ts
+@Component({
+  // ...
+})
 export class BlogPostComponent {
   postId = input.required<number>()
   queryClient = inject(QueryClient)
diff --git a/docs/framework/angular/guides/queries.md b/docs/framework/angular/guides/queries.md
index 336da2e171..8192f927f0 100644
--- a/docs/framework/angular/guides/queries.md
+++ b/docs/framework/angular/guides/queries.md
@@ -19,6 +19,9 @@ replace:
 ```ts
 import { injectQuery } from '@tanstack/angular-query-experimental'
 
+@Component({
+  // ...
+})
 export class TodosComponent {
   info = injectQuery(() => ({ queryKey: ['todos'], queryFn: fetchTodoList }))
 }
@@ -61,38 +64,7 @@ export class PostsComponent {
 ```
 
 [//]: # 'Example3'
-
-If booleans aren't your thing, you can always use the `status` state as well:
-
 [//]: # 'Example4'
-
-```angular-ts
-@Component({
-  selector: 'todos',
-  template: `
-    @switch (todos.status()) {
-      @case ('pending') {
-        <span>Loading...</span>
-      }
-      @case ('error') {
-        <span>Error: {{ todos.error()?.message }}</span>
-      }
-      <!-- also status === 'success', but "else" logic works, too -->
-      @default {
-        <ul>
-          @for (todo of todos.data(); track todo.id) {
-            <li>{{ todo.title }}</li>
-          } @empty {
-            <li>No todos found</li>
-          }
-        </ul>
-      }
-    }
-  `,
-})
-class TodosComponent {}
-```
-
 [//]: # 'Example4'
 [//]: # 'Materials'
 [//]: # 'Materials'
diff --git a/docs/framework/angular/guides/query-functions.md b/docs/framework/angular/guides/query-functions.md
index ae5f9e6c99..c8c3bd992a 100644
--- a/docs/framework/angular/guides/query-functions.md
+++ b/docs/framework/angular/guides/query-functions.md
@@ -8,16 +8,19 @@ ref: docs/framework/react/guides/query-functions.md
 
 ```ts
 injectQuery(() => ({ queryKey: ['todos'], queryFn: fetchAllTodos }))
-injectQuery(() => ({ queryKey: ['todos', todoId], queryFn: () => fetchTodoById(todoId) })
 injectQuery(() => ({
-  queryKey: ['todos', todoId],
+  queryKey: ['todos', todoId()],
+  queryFn: () => fetchTodoById(todoId()),
+}))
+injectQuery(() => ({
+  queryKey: ['todos', todoId()],
   queryFn: async () => {
-    const data = await fetchTodoById(todoId)
+    const data = await fetchTodoById(todoId())
     return data
   },
 }))
 injectQuery(() => ({
-  queryKey: ['todos', todoId],
+  queryKey: ['todos', todoId()],
   queryFn: ({ queryKey }) => fetchTodoById(queryKey[1]),
 }))
 ```
@@ -26,8 +29,10 @@ injectQuery(() => ({
 [//]: # 'Example2'
 
 ```ts
+todoId = signal(1)
+
 todos = injectQuery(() => ({
-  queryKey: ['todos', todoId()],
+  queryKey: ['todos', this.todoId()],
   queryFn: async () => {
     if (somethingGoesWrong) {
       throw new Error('Oh no!')
@@ -45,10 +50,12 @@ todos = injectQuery(() => ({
 [//]: # 'Example3'
 
 ```ts
+todoId = signal(1)
+
 todos = injectQuery(() => ({
-  queryKey: ['todos', todoId()],
+  queryKey: ['todos', this.todoId()],
   queryFn: async () => {
-    const response = await fetch('/todos/' + todoId)
+    const response = await fetch('/todos/' + this.todoId())
     if (!response.ok) {
       throw new Error('Network response was not ok')
     }
@@ -61,8 +68,11 @@ todos = injectQuery(() => ({
 [//]: # 'Example4'
 
 ```ts
+status = signal('active')
+page = signal(1)
+
 result = injectQuery(() => ({
-  queryKey: ['todos', { status: status(), page: page() }],
+  queryKey: ['todos', { status: this.status(), page: this.page() }],
   queryFn: fetchTodoList,
 }))
 
diff --git a/docs/framework/angular/guides/query-invalidation.md b/docs/framework/angular/guides/query-invalidation.md
index 9cd8ea5809..e174d0a4b4 100644
--- a/docs/framework/angular/guides/query-invalidation.md
+++ b/docs/framework/angular/guides/query-invalidation.md
@@ -8,8 +8,12 @@ replace: { 'useQuery': 'injectQuery', 'hooks': 'functions' }
 [//]: # 'Example2'
 
 ```ts
+import { Component, inject } from '@angular/core'
 import { injectQuery, QueryClient } from '@tanstack/angular-query-experimental'
 
+@Component({
+  // ...
+})
 class QueryInvalidationExample {
   queryClient = inject(QueryClient)
 
@@ -72,7 +76,7 @@ todoListQuery = injectQuery(() => ({
 }))
 
 // However, the following query below will NOT be invalidated
-const todoListQuery = injectQuery(() => ({
+todoListQuery = injectQuery(() => ({
   queryKey: ['todos', { type: 'done' }],
   queryFn: fetchTodoList,
 }))
diff --git a/docs/framework/angular/guides/query-options.md b/docs/framework/angular/guides/query-options.md
index d63753bbfc..6d6ad6b3e9 100644
--- a/docs/framework/angular/guides/query-options.md
+++ b/docs/framework/angular/guides/query-options.md
@@ -31,26 +31,26 @@ export class QueriesService {
 
 // usage:
 
-postId = input.required({
-  transform: numberAttribute,
-})
+postId = input.required({ transform: numberAttribute })
 queries = inject(QueriesService)
+queryClient = inject(QueryClient)
 
 postQuery = injectQuery(() => this.queries.post(this.postId()))
 
-queryClient.prefetchQuery(this.queries.post(23))
-queryClient.setQueryData(this.queries.post(42).queryKey, newPost)
+someMethod() {
+  this.queryClient.prefetchQuery(this.queries.post(23))
+  this.queryClient.setQueryData(this.queries.post(42).queryKey, newPost)
+}
 ```
 
 [//]: # 'Example1'
 [//]: # 'Example2'
 
 ```ts
-// Type inference still works, so query.data will be the return type of select instead of queryFn
 queries = inject(QueriesService)
 
 query = injectQuery(() => ({
-  ...groupOptions(1),
+  ...this.queries.post(1),
   select: (data) => data.title,
 }))
 ```
diff --git a/docs/framework/angular/guides/query-retries.md b/docs/framework/angular/guides/query-retries.md
index 45228d10bb..c6c73fb280 100644
--- a/docs/framework/angular/guides/query-retries.md
+++ b/docs/framework/angular/guides/query-retries.md
@@ -31,10 +31,10 @@ const result = injectQuery(() => ({
 ```ts
 // Configure for all queries
 import {
-  QueryCache,
   QueryClient,
-  QueryClientProvider,
+  provideTanStackQuery,
 } from '@tanstack/angular-query-experimental'
+import { bootstrapApplication } from '@angular/platform-browser'
 
 const queryClient = new QueryClient({
   defaultOptions: {
@@ -51,7 +51,7 @@ bootstrapApplication(AppComponent, {
 
 [//]: # 'Example2'
 
-Though it is not recommended, you can obviously override the `retryDelay` function/integer in both the Provider and individual query options. If set to an integer instead of a function the delay will always be the same amount of time:
+Though it is not recommended, you can obviously override the `retryDelay` function/integer in both the QueryClient default options and individual query options. If set to an integer instead of a function the delay will always be the same amount of time:
 
 [//]: # 'Example3'
 
diff --git a/docs/framework/angular/guides/testing.md b/docs/framework/angular/guides/testing.md
index 7648d7f6b3..91d9575dbc 100644
--- a/docs/framework/angular/guides/testing.md
+++ b/docs/framework/angular/guides/testing.md
@@ -7,9 +7,7 @@ Most Angular tests using TanStack Query will involve services or components that
 
 TanStack Query's `inject*` functions integrate with [`PendingTasks`](https://angular.dev/api/core/PendingTasks) which ensures the framework is aware of in-progress queries and mutations.
 
-This means tests and SSR can wait until mutations and queries resolve. In unit tests you can use `ApplicationRef.whenStable()` or `fixture.whenStable()` to await query completion. This works for both Zone.js and Zoneless setups.
-
-> This integration requires Angular 19 or later. Earlier versions of Angular do not support `PendingTasks`.
+This means tests and SSR can wait until mutations and queries resolve. In unit tests you can use `ApplicationRef.whenStable()` or `fixture.whenStable()` to await query completion. The examples below use a zoneless TestBed setup.
 
 ## TestBed setup
 
@@ -31,7 +29,7 @@ TestBed.configureTestingModule({
 
 > If your applications actual TanStack Query config is used in unit tests, make sure `withDevtools` is not accidentally included in test providers. This can cause slow tests. It is best to keep test and production configs separate.
 
-If you share helpers, remember to call `queryClient.clear()` (or build a new instance) in `afterEach` so data from one test never bleeds into another.
+If you share helpers, remember to call `queryClient.clear()` (or build a new instance) in `afterEach` so data from one test never bleeds into another. Prefer creating a fresh `QueryClient` per test: clearing only removes cached data, not custom defaults or listeners, so a reused client can leak configuration changes between specs and make failures harder to reason about. A new client keeps setup explicit and avoids any “invisible globals” influencing results.
 
 ## First query test
 
diff --git a/docs/framework/angular/installation.md b/docs/framework/angular/installation.md
index dffc092e7c..14b48432f8 100644
--- a/docs/framework/angular/installation.md
+++ b/docs/framework/angular/installation.md
@@ -7,7 +7,7 @@ title: Installation
 
 ### NPM
 
-_Angular Query is compatible with Angular v16 and higher_
+_Angular Query is compatible with Angular v19 and higher_
 
 ```bash
 npm i @tanstack/angular-query-experimental
diff --git a/docs/framework/angular/overview.md b/docs/framework/angular/overview.md
index be68c08e5a..2eba20cab0 100644
--- a/docs/framework/angular/overview.md
+++ b/docs/framework/angular/overview.md
@@ -13,7 +13,7 @@ We are in the process of getting to a stable API for TanStack Query on Angular.
 
 ## Supported Angular Versions
 
-TanStack Query is compatible with Angular v16 and higher.
+TanStack Query is compatible with Angular v19 and higher.
 
 TanStack Query (FKA React Query) is often described as the missing data-fetching library for web applications, but in more technical terms, it makes **fetching, caching, synchronizing and updating server state** in your web applications a breeze.
 
@@ -73,11 +73,10 @@ import { lastValueFrom } from 'rxjs'
   template: `
     @if (query.isPending()) {
       Loading...
-    }
-    @if (query.error()) {
+    } @else if (query.isError()) {
       An error has occurred: {{ query.error().message }}
-    }
-    @if (query.data(); as data) {
+    } @else if (query.isSuccess()) {
+      @let data = query.data();
       <h1>{{ data.name }}</h1>
       <p>{{ data.description }}</p>
       <strong>👀 {{ data.subscribers_count }}</strong>
diff --git a/docs/framework/angular/quick-start.md b/docs/framework/angular/quick-start.md
index b711f92b2b..41b246498d 100644
--- a/docs/framework/angular/quick-start.md
+++ b/docs/framework/angular/quick-start.md
@@ -35,7 +35,7 @@ import {
 @NgModule({
   declarations: [AppComponent],
   imports: [BrowserModule],
-  providers: [provideTanStackQuery(new QueryClient())],
+  providers: [provideTanStackQuery(new QueryClient()), provideHttpClient()],
   bootstrap: [AppComponent],
 })
 export class AppModule {}
diff --git a/docs/framework/angular/reference/functions/injectInfiniteQuery.md b/docs/framework/angular/reference/functions/injectInfiniteQuery.md
index 020ef039fa..7e09345bc8 100644
--- a/docs/framework/angular/reference/functions/injectInfiniteQuery.md
+++ b/docs/framework/angular/reference/functions/injectInfiniteQuery.md
@@ -22,7 +22,7 @@ Additional configuration.
 function injectInfiniteQuery<TQueryFnData, TError, TData, TQueryKey, TPageParam>(injectInfiniteQueryFn, options?): DefinedCreateInfiniteQueryResult<TData, TError>;
 ```
 
-Defined in: [inject-infinite-query.ts:41](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-infinite-query.ts#L41)
+Defined in: [inject-infinite-query.ts:43](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-infinite-query.ts#L43)
 
 Injects an infinite query: a declarative dependency on an asynchronous source of data that is tied to a unique key.
 Infinite queries can additively "load more" data onto an existing set of data or "infinite scroll"
@@ -75,7 +75,7 @@ The infinite query result.
 function injectInfiniteQuery<TQueryFnData, TError, TData, TQueryKey, TPageParam>(injectInfiniteQueryFn, options?): CreateInfiniteQueryResult<TData, TError>;
 ```
 
-Defined in: [inject-infinite-query.ts:65](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-infinite-query.ts#L65)
+Defined in: [inject-infinite-query.ts:67](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-infinite-query.ts#L67)
 
 Injects an infinite query: a declarative dependency on an asynchronous source of data that is tied to a unique key.
 Infinite queries can additively "load more" data onto an existing set of data or "infinite scroll"
@@ -128,7 +128,7 @@ The infinite query result.
 function injectInfiniteQuery<TQueryFnData, TError, TData, TQueryKey, TPageParam>(injectInfiniteQueryFn, options?): CreateInfiniteQueryResult<TData, TError>;
 ```
 
-Defined in: [inject-infinite-query.ts:89](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-infinite-query.ts#L89)
+Defined in: [inject-infinite-query.ts:91](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-infinite-query.ts#L91)
 
 Injects an infinite query: a declarative dependency on an asynchronous source of data that is tied to a unique key.
 Infinite queries can additively "load more" data onto an existing set of data or "infinite scroll"
diff --git a/docs/framework/angular/reference/functions/injectMutation.md b/docs/framework/angular/reference/functions/injectMutation.md
index 5b4690eb46..8b2adfd525 100644
--- a/docs/framework/angular/reference/functions/injectMutation.md
+++ b/docs/framework/angular/reference/functions/injectMutation.md
@@ -9,7 +9,7 @@ title: injectMutation
 function injectMutation<TData, TError, TVariables, TOnMutateResult>(injectMutationFn, options?): CreateMutationResult<TData, TError, TVariables, TOnMutateResult>;
 ```
 
-Defined in: [inject-mutation.ts:45](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-mutation.ts#L45)
+Defined in: [inject-mutation.ts:44](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-mutation.ts#L44)
 
 Injects a mutation: an imperative function that can be invoked which typically performs server side effects.
 
diff --git a/docs/framework/angular/reference/functions/injectQueries.md b/docs/framework/angular/reference/functions/injectQueries.md
new file mode 100644
index 0000000000..d05f95e379
--- /dev/null
+++ b/docs/framework/angular/reference/functions/injectQueries.md
@@ -0,0 +1,40 @@
+---
+id: injectQueries
+title: injectQueries
+---
+
+# Function: injectQueries()
+
+```ts
+function injectQueries<T, TCombinedResult>(optionsFn, injector?): Signal<TCombinedResult>;
+```
+
+Defined in: [inject-queries.ts:278](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-queries.ts#L278)
+
+## Type Parameters
+
+### T
+
+`T` *extends* `any`[]
+
+### TCombinedResult
+
+`TCombinedResult` = `T` *extends* \[\] ? \[\] : `T` *extends* \[`Head`\] ? \[`GenericGetDefinedOrUndefinedQueryResult`\<`Head`, `InferDataAndError`\<`Head`\>\[`"data"`\], [`CreateQueryResult`](../type-aliases/CreateQueryResult.md)\<`InferDataAndError`\<`Head`\>\[`"data"`\], `InferDataAndError`\<`Head`\>\[`"error"`\]\>, [`DefinedCreateQueryResult`](../type-aliases/DefinedCreateQueryResult.md)\<`InferDataAndError`\<`Head`\>\[`"data"`\], `InferDataAndError`\<`Head`\>\[`"error"`\]\>\>\] : `T` *extends* \[`Head`, `...Tails[]`\] ? \[`...Tails[]`\] *extends* \[\] ? \[\] : \[`...Tails[]`\] *extends* \[`Head`\] ? \[`GenericGetDefinedOrUndefinedQueryResult`\<`Head`, `InferDataAndError`\<`Head`\>\[`"data"`\], [`CreateQueryResult`](../type-aliases/CreateQueryResult.md)\<`InferDataAndError`\<`Head`\>\[`"data"`\], `InferDataAndError`\<`Head`\>\[`"error"`\]\>, [`DefinedCreateQueryResult`](../type-aliases/DefinedCreateQueryResult.md)\<`InferDataAndError`\<`Head`\>\[`"data"`\], `InferDataAndError`\<`Head`\>\[`"error"`\]\>\>, `GenericGetDefinedOrUndefinedQueryResult`\<`Head`, `InferDataAndError`\<`Head`\>\[`"data"`\], [`CreateQueryResult`](../type-aliases/CreateQueryResult.md)\<`InferDataAndError`\<`Head`\>\[`"data"`\], `InferDataAndError`\<`Head`\>\[`"error"`\]\>, [`DefinedCreateQueryResult`](../type-aliases/DefinedCreateQueryResult.md)\<`InferDataAndError`\<`Head`\>\[`"data"`\], `InferDataAndError`\<`Head`\>\[`"error"`\]\>\>\] : \[`...Tails[]`\] *extends* \[`Head`, `...Tails[]`\] ? \[`...Tails[]`\] *extends* \[\] ? \[\] : \[`...Tails[]`\] *extends* \[`Head`\] ? \[`GenericGetDefinedOrUndefinedQueryResult`\<`Head`, ...\[...\], [`CreateQueryResult`](../type-aliases/CreateQueryResult.md)\<..., ...\>, [`DefinedCreateQueryResult`](../type-aliases/DefinedCreateQueryResult.md)\<..., ...\>\>, `GenericGetDefinedOrUndefinedQueryResult`\<`Head`, ...\[...\], [`CreateQueryResult`](../type-aliases/CreateQueryResult.md)\<..., ...\>, [`DefinedCreateQueryResult`](../type-aliases/DefinedCreateQueryResult.md)\<..., ...\>\>, `GenericGetDefinedOrUndefinedQueryResult`\<`Head`, ...\[...\], [`CreateQueryResult`](../type-aliases/CreateQueryResult.md)\<..., ...\>, [`DefinedCreateQueryResult`](../type-aliases/DefinedCreateQueryResult.md)\<..., ...\>\>\] : \[`...Tails[]`\] *extends* \[`Head`, `...Tails[]`\] ? \[`...(...)[]`\] *extends* \[\] ? \[\] : ... *extends* ... ? ... : ... : \[`...{ [K in (...)]: (...) }[]`\] : \[...\{ \[K in string \| number \| symbol\]: GenericGetDefinedOrUndefinedQueryResult\<Tails\[K\<(...)\>\], InferDataAndError\<(...)\>\["data"\], CreateQueryResult\<(...)\[(...)\], (...)\[(...)\]\>, DefinedCreateQueryResult\<(...)\[(...)\], (...)\[(...)\]\>\> \}\[\]\] : \{ \[K in string \| number \| symbol\]: GenericGetDefinedOrUndefinedQueryResult\<T\[K\<K\>\], InferDataAndError\<T\[K\<K\>\]\>\["data"\], CreateQueryResult\<InferDataAndError\<T\[K\<K\>\]\>\["data"\], InferDataAndError\<T\[K\<K\>\]\>\["error"\]\>, DefinedCreateQueryResult\<InferDataAndError\<T\[K\<K\>\]\>\["data"\], InferDataAndError\<T\[K\<K\>\]\>\["error"\]\>\> \}
+
+## Parameters
+
+### optionsFn
+
+() => [`InjectQueriesOptions`](../interfaces/InjectQueriesOptions.md)\<`T`, `TCombinedResult`\>
+
+A function that returns queries' options.
+
+### injector?
+
+`Injector`
+
+The Angular injector to use.
+
+## Returns
+
+`Signal`\<`TCombinedResult`\>
diff --git a/docs/framework/angular/reference/functions/injectQuery.md b/docs/framework/angular/reference/functions/injectQuery.md
index 8fa6832b09..63ffbeb92b 100644
--- a/docs/framework/angular/reference/functions/injectQuery.md
+++ b/docs/framework/angular/reference/functions/injectQuery.md
@@ -9,11 +9,15 @@ Injects a query: a declarative dependency on an asynchronous source of data that
 
 **Basic example**
 ```ts
+import { lastValueFrom } from 'rxjs'
+
 class ServiceOrComponent {
   query = injectQuery(() => ({
     queryKey: ['repoData'],
     queryFn: () =>
-      this.#http.get<Response>('https://api.github.com/repos/tanstack/query'),
+      lastValueFrom(
+        this.#http.get<Response>('https://api.github.com/repos/tanstack/query'),
+      ),
   }))
 }
 ```
@@ -54,17 +58,21 @@ https://tanstack.com/query/latest/docs/framework/angular/guides/queries
 function injectQuery<TQueryFnData, TError, TData, TQueryKey>(injectQueryFn, options?): DefinedCreateQueryResult<TData, TError>;
 ```
 
-Defined in: [inject-query.ts:65](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-query.ts#L65)
+Defined in: [inject-query.ts:74](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-query.ts#L74)
 
 Injects a query: a declarative dependency on an asynchronous source of data that is tied to a unique key.
 
 **Basic example**
 ```ts
+import { lastValueFrom } from 'rxjs'
+
 class ServiceOrComponent {
   query = injectQuery(() => ({
     queryKey: ['repoData'],
     queryFn: () =>
-      this.#http.get<Response>('https://api.github.com/repos/tanstack/query'),
+      lastValueFrom(
+        this.#http.get<Response>('https://api.github.com/repos/tanstack/query'),
+      ),
   }))
 }
 ```
@@ -135,17 +143,21 @@ https://tanstack.com/query/latest/docs/framework/angular/guides/queries
 function injectQuery<TQueryFnData, TError, TData, TQueryKey>(injectQueryFn, options?): CreateQueryResult<TData, TError>;
 ```
 
-Defined in: [inject-query.ts:116](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-query.ts#L116)
+Defined in: [inject-query.ts:129](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-query.ts#L129)
 
 Injects a query: a declarative dependency on an asynchronous source of data that is tied to a unique key.
 
 **Basic example**
 ```ts
+import { lastValueFrom } from 'rxjs'
+
 class ServiceOrComponent {
   query = injectQuery(() => ({
     queryKey: ['repoData'],
     queryFn: () =>
-      this.#http.get<Response>('https://api.github.com/repos/tanstack/query'),
+      lastValueFrom(
+        this.#http.get<Response>('https://api.github.com/repos/tanstack/query'),
+      ),
   }))
 }
 ```
@@ -216,17 +228,21 @@ https://tanstack.com/query/latest/docs/framework/angular/guides/queries
 function injectQuery<TQueryFnData, TError, TData, TQueryKey>(injectQueryFn, options?): CreateQueryResult<TData, TError>;
 ```
 
-Defined in: [inject-query.ts:167](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-query.ts#L167)
+Defined in: [inject-query.ts:184](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-query.ts#L184)
 
 Injects a query: a declarative dependency on an asynchronous source of data that is tied to a unique key.
 
 **Basic example**
 ```ts
+import { lastValueFrom } from 'rxjs'
+
 class ServiceOrComponent {
   query = injectQuery(() => ({
     queryKey: ['repoData'],
     queryFn: () =>
-      this.#http.get<Response>('https://api.github.com/repos/tanstack/query'),
+      lastValueFrom(
+        this.#http.get<Response>('https://api.github.com/repos/tanstack/query'),
+      ),
   }))
 }
 ```
@@ -271,7 +287,7 @@ class ServiceOrComponent {
 
 #### injectQueryFn
 
-() => [`CreateQueryOptions`](../interfaces/CreateQueryOptions.md)\<`TQueryFnData`, `TError`, `TData`, `TQueryKey`\>
+() => [`CreateQueryOptions`](../type-aliases/CreateQueryOptions.md)\<`TQueryFnData`, `TError`, `TData`, `TQueryKey`\>
 
 A function that returns query options.
 
diff --git a/docs/framework/angular/reference/functions/queryOptions.md b/docs/framework/angular/reference/functions/queryOptions.md
index 34640111ec..70f1b3fb0e 100644
--- a/docs/framework/angular/reference/functions/queryOptions.md
+++ b/docs/framework/angular/reference/functions/queryOptions.md
@@ -30,10 +30,10 @@ The query options to tag with the type from `queryFn`.
 ## Call Signature
 
 ```ts
-function queryOptions<TQueryFnData, TError, TData, TQueryKey>(options): Omit<CreateQueryOptions<TQueryFnData, TError, TData, TQueryKey>, "queryFn"> & object & object;
+function queryOptions<TQueryFnData, TError, TData, TQueryKey>(options): CreateQueryOptions<TQueryFnData, TError, TData, TQueryKey> & object & object;
 ```
 
-Defined in: [query-options.ts:76](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/query-options.ts#L76)
+Defined in: [query-options.ts:71](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/query-options.ts#L71)
 
 Allows to share and re-use query options in a type-safe way.
 
@@ -81,7 +81,7 @@ The query options to tag with the type from `queryFn`.
 
 ### Returns
 
-`Omit`\<[`CreateQueryOptions`](../interfaces/CreateQueryOptions.md)\<`TQueryFnData`, `TError`, `TData`, `TQueryKey`\>, `"queryFn"`\> & `object` & `object`
+[`CreateQueryOptions`](../type-aliases/CreateQueryOptions.md)\<`TQueryFnData`, `TError`, `TData`, `TQueryKey`\> & `object` & `object`
 
 The tagged query options.
 
@@ -91,7 +91,7 @@ The tagged query options.
 function queryOptions<TQueryFnData, TError, TData, TQueryKey>(options): OmitKeyof<CreateQueryOptions<TQueryFnData, TError, TData, TQueryKey>, "queryFn"> & object & object;
 ```
 
-Defined in: [query-options.ts:108](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/query-options.ts#L108)
+Defined in: [query-options.ts:103](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/query-options.ts#L103)
 
 Allows to share and re-use query options in a type-safe way.
 
@@ -139,7 +139,7 @@ The query options to tag with the type from `queryFn`.
 
 ### Returns
 
-`OmitKeyof`\<[`CreateQueryOptions`](../interfaces/CreateQueryOptions.md)\<`TQueryFnData`, `TError`, `TData`, `TQueryKey`\>, `"queryFn"`\> & `object` & `object`
+`OmitKeyof`\<[`CreateQueryOptions`](../type-aliases/CreateQueryOptions.md)\<`TQueryFnData`, `TError`, `TData`, `TQueryKey`\>, `"queryFn"`\> & `object` & `object`
 
 The tagged query options.
 
@@ -149,7 +149,7 @@ The tagged query options.
 function queryOptions<TQueryFnData, TError, TData, TQueryKey>(options): CreateQueryOptions<TQueryFnData, TError, TData, TQueryKey> & object & object;
 ```
 
-Defined in: [query-options.ts:140](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/query-options.ts#L140)
+Defined in: [query-options.ts:135](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/query-options.ts#L135)
 
 Allows to share and re-use query options in a type-safe way.
 
@@ -197,6 +197,6 @@ The query options to tag with the type from `queryFn`.
 
 ### Returns
 
-[`CreateQueryOptions`](../interfaces/CreateQueryOptions.md)\<`TQueryFnData`, `TError`, `TData`, `TQueryKey`\> & `object` & `object`
+[`CreateQueryOptions`](../type-aliases/CreateQueryOptions.md)\<`TQueryFnData`, `TError`, `TData`, `TQueryKey`\> & `object` & `object`
 
 The tagged query options.
diff --git a/docs/framework/angular/reference/index.md b/docs/framework/angular/reference/index.md
index c74d256bce..16da72ce20 100644
--- a/docs/framework/angular/reference/index.md
+++ b/docs/framework/angular/reference/index.md
@@ -9,26 +9,27 @@ title: "@tanstack/angular-query-experimental"
 
 - [BaseMutationNarrowing](interfaces/BaseMutationNarrowing.md)
 - [BaseQueryNarrowing](interfaces/BaseQueryNarrowing.md)
-- [CreateBaseQueryOptions](interfaces/CreateBaseQueryOptions.md)
 - [CreateInfiniteQueryOptions](interfaces/CreateInfiniteQueryOptions.md)
 - [CreateMutationOptions](interfaces/CreateMutationOptions.md)
-- [CreateQueryOptions](interfaces/CreateQueryOptions.md)
 - [InjectInfiniteQueryOptions](interfaces/InjectInfiniteQueryOptions.md)
 - [InjectIsFetchingOptions](interfaces/InjectIsFetchingOptions.md)
 - [InjectIsMutatingOptions](interfaces/InjectIsMutatingOptions.md)
 - [InjectMutationOptions](interfaces/InjectMutationOptions.md)
 - [InjectMutationStateOptions](interfaces/InjectMutationStateOptions.md)
+- [InjectQueriesOptions](interfaces/InjectQueriesOptions.md)
 - [InjectQueryOptions](interfaces/InjectQueryOptions.md)
 - [QueryFeature](interfaces/QueryFeature.md)
 
 ## Type Aliases
 
 - [CreateBaseMutationResult](type-aliases/CreateBaseMutationResult.md)
+- [CreateBaseQueryOptions](type-aliases/CreateBaseQueryOptions.md)
 - [CreateBaseQueryResult](type-aliases/CreateBaseQueryResult.md)
 - [CreateInfiniteQueryResult](type-aliases/CreateInfiniteQueryResult.md)
 - [CreateMutateAsyncFunction](type-aliases/CreateMutateAsyncFunction.md)
 - [CreateMutateFunction](type-aliases/CreateMutateFunction.md)
 - [CreateMutationResult](type-aliases/CreateMutationResult.md)
+- [CreateQueryOptions](type-aliases/CreateQueryOptions.md)
 - [CreateQueryResult](type-aliases/CreateQueryResult.md)
 - [DefinedCreateInfiniteQueryResult](type-aliases/DefinedCreateInfiniteQueryResult.md)
 - [DefinedCreateQueryResult](type-aliases/DefinedCreateQueryResult.md)
@@ -53,6 +54,7 @@ title: "@tanstack/angular-query-experimental"
 - [injectIsRestoring](functions/injectIsRestoring.md)
 - [injectMutation](functions/injectMutation.md)
 - [injectMutationState](functions/injectMutationState.md)
+- [injectQueries](functions/injectQueries.md)
 - [injectQuery](functions/injectQuery.md)
 - [~~injectQueryClient~~](functions/injectQueryClient.md)
 - [mutationOptions](functions/mutationOptions.md)
diff --git a/docs/framework/angular/reference/interfaces/BaseQueryNarrowing.md b/docs/framework/angular/reference/interfaces/BaseQueryNarrowing.md
index bc7811b6ae..24a00f39cb 100644
--- a/docs/framework/angular/reference/interfaces/BaseQueryNarrowing.md
+++ b/docs/framework/angular/reference/interfaces/BaseQueryNarrowing.md
@@ -5,7 +5,7 @@ title: BaseQueryNarrowing
 
 # Interface: BaseQueryNarrowing\<TData, TError\>
 
-Defined in: [types.ts:57](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L57)
+Defined in: [types.ts:45](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L45)
 
 ## Type Parameters
 
@@ -25,7 +25,7 @@ Defined in: [types.ts:57](https://github.com/TanStack/query/blob/main/packages/a
 isError: (this) => this is CreateBaseQueryResult<TData, TError, CreateStatusBasedQueryResult<"error", TData, TError>>;
 ```
 
-Defined in: [types.ts:65](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L65)
+Defined in: [types.ts:53](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L53)
 
 #### Parameters
 
@@ -45,7 +45,7 @@ Defined in: [types.ts:65](https://github.com/TanStack/query/blob/main/packages/a
 isPending: (this) => this is CreateBaseQueryResult<TData, TError, CreateStatusBasedQueryResult<"pending", TData, TError>>;
 ```
 
-Defined in: [types.ts:72](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L72)
+Defined in: [types.ts:60](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L60)
 
 #### Parameters
 
@@ -65,7 +65,7 @@ Defined in: [types.ts:72](https://github.com/TanStack/query/blob/main/packages/a
 isSuccess: (this) => this is CreateBaseQueryResult<TData, TError, CreateStatusBasedQueryResult<"success", TData, TError>>;
 ```
 
-Defined in: [types.ts:58](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L58)
+Defined in: [types.ts:46](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L46)
 
 #### Parameters
 
diff --git a/docs/framework/angular/reference/interfaces/CreateInfiniteQueryOptions.md b/docs/framework/angular/reference/interfaces/CreateInfiniteQueryOptions.md
index ab21d5bc32..1f8883c8d7 100644
--- a/docs/framework/angular/reference/interfaces/CreateInfiniteQueryOptions.md
+++ b/docs/framework/angular/reference/interfaces/CreateInfiniteQueryOptions.md
@@ -5,7 +5,7 @@ title: CreateInfiniteQueryOptions
 
 # Interface: CreateInfiniteQueryOptions\<TQueryFnData, TError, TData, TQueryKey, TPageParam\>
 
-Defined in: [types.ts:81](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L81)
+Defined in: [types.ts:69](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L69)
 
 ## Extends
 
diff --git a/docs/framework/angular/reference/interfaces/CreateQueryOptions.md b/docs/framework/angular/reference/interfaces/CreateQueryOptions.md
deleted file mode 100644
index 113fbbc5d2..0000000000
--- a/docs/framework/angular/reference/interfaces/CreateQueryOptions.md
+++ /dev/null
@@ -1,30 +0,0 @@
----
-id: CreateQueryOptions
-title: CreateQueryOptions
----
-
-# Interface: CreateQueryOptions\<TQueryFnData, TError, TData, TQueryKey\>
-
-Defined in: [types.ts:35](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L35)
-
-## Extends
-
-- `OmitKeyof`\<[`CreateBaseQueryOptions`](CreateBaseQueryOptions.md)\<`TQueryFnData`, `TError`, `TData`, `TQueryFnData`, `TQueryKey`\>, `"suspense"`\>
-
-## Type Parameters
-
-### TQueryFnData
-
-`TQueryFnData` = `unknown`
-
-### TError
-
-`TError` = `DefaultError`
-
-### TData
-
-`TData` = `TQueryFnData`
-
-### TQueryKey
-
-`TQueryKey` *extends* `QueryKey` = `QueryKey`
diff --git a/docs/framework/angular/reference/interfaces/InjectInfiniteQueryOptions.md b/docs/framework/angular/reference/interfaces/InjectInfiniteQueryOptions.md
index 3b552aa381..33880ffae2 100644
--- a/docs/framework/angular/reference/interfaces/InjectInfiniteQueryOptions.md
+++ b/docs/framework/angular/reference/interfaces/InjectInfiniteQueryOptions.md
@@ -5,7 +5,7 @@ title: InjectInfiniteQueryOptions
 
 # Interface: InjectInfiniteQueryOptions
 
-Defined in: [inject-infinite-query.ts:25](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-infinite-query.ts#L25)
+Defined in: [inject-infinite-query.ts:27](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-infinite-query.ts#L27)
 
 ## Properties
 
@@ -15,7 +15,7 @@ Defined in: [inject-infinite-query.ts:25](https://github.com/TanStack/query/blob
 optional injector: Injector;
 ```
 
-Defined in: [inject-infinite-query.ts:31](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-infinite-query.ts#L31)
+Defined in: [inject-infinite-query.ts:33](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-infinite-query.ts#L33)
 
 The `Injector` in which to create the infinite query.
 
diff --git a/docs/framework/angular/reference/interfaces/InjectMutationOptions.md b/docs/framework/angular/reference/interfaces/InjectMutationOptions.md
index 0638baa372..c313951b25 100644
--- a/docs/framework/angular/reference/interfaces/InjectMutationOptions.md
+++ b/docs/framework/angular/reference/interfaces/InjectMutationOptions.md
@@ -5,7 +5,7 @@ title: InjectMutationOptions
 
 # Interface: InjectMutationOptions
 
-Defined in: [inject-mutation.ts:28](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-mutation.ts#L28)
+Defined in: [inject-mutation.ts:27](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-mutation.ts#L27)
 
 ## Properties
 
@@ -15,7 +15,7 @@ Defined in: [inject-mutation.ts:28](https://github.com/TanStack/query/blob/main/
 optional injector: Injector;
 ```
 
-Defined in: [inject-mutation.ts:34](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-mutation.ts#L34)
+Defined in: [inject-mutation.ts:33](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-mutation.ts#L33)
 
 The `Injector` in which to create the mutation.
 
diff --git a/docs/framework/angular/reference/interfaces/InjectQueriesOptions.md b/docs/framework/angular/reference/interfaces/InjectQueriesOptions.md
new file mode 100644
index 0000000000..c9f860b872
--- /dev/null
+++ b/docs/framework/angular/reference/interfaces/InjectQueriesOptions.md
@@ -0,0 +1,50 @@
+---
+id: InjectQueriesOptions
+title: InjectQueriesOptions
+---
+
+# Interface: InjectQueriesOptions\<T, TCombinedResult\>
+
+Defined in: [inject-queries.ts:257](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-queries.ts#L257)
+
+## Type Parameters
+
+### T
+
+`T` *extends* `any`[]
+
+### TCombinedResult
+
+`TCombinedResult` = [`QueriesResults`](../type-aliases/QueriesResults.md)\<`T`\>
+
+## Properties
+
+### combine()?
+
+```ts
+optional combine: (result) => TCombinedResult;
+```
+
+Defined in: [inject-queries.ts:266](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-queries.ts#L266)
+
+#### Parameters
+
+##### result
+
+`T` *extends* \[\] ? \[\] : `T` *extends* \[`Head`\] ? \[`GenericGetDefinedOrUndefinedQueryResult`\<`Head`, `InferDataAndError`\<`Head`\>\[`"data"`\], `QueryObserverResult`\<`InferDataAndError`\<`Head`\>\[`"data"`\], `InferDataAndError`\<`Head`\>\[`"error"`\]\>, `DefinedQueryObserverResult`\<`InferDataAndError`\<`Head`\>\[`"data"`\], `InferDataAndError`\<`Head`\>\[`"error"`\]\>\>\] : `T` *extends* \[`Head`, `...Tails[]`\] ? \[`...Tails[]`\] *extends* \[\] ? \[\] : \[`...Tails[]`\] *extends* \[`Head`\] ? \[`GenericGetDefinedOrUndefinedQueryResult`\<`Head`, `InferDataAndError`\<...\>\[`"data"`\], `QueryObserverResult`\<...\[...\], ...\[...\]\>, `DefinedQueryObserverResult`\<...\[...\], ...\[...\]\>\>, `GenericGetDefinedOrUndefinedQueryResult`\<`Head`, `InferDataAndError`\<...\>\[`"data"`\], `QueryObserverResult`\<...\[...\], ...\[...\]\>, `DefinedQueryObserverResult`\<...\[...\], ...\[...\]\>\>\] : \[`...Tails[]`\] *extends* \[`Head`, `...Tails[]`\] ? \[`...Tails[]`\] *extends* \[\] ? \[\] : \[`...(...)[]`\] *extends* \[...\] ? \[..., ..., ...\] : ... *extends* ... ? ... : ... : \[...\{ \[K in (...) \| (...) \| (...)\]: GenericGetDefinedOrUndefinedQueryResult\<(...), (...), (...), (...)\> \}\[\]\] : \{ \[K in string \| number \| symbol\]: GenericGetDefinedOrUndefinedQueryResult\<T\[K\<K\>\], InferDataAndError\<T\[K\<(...)\>\]\>\["data"\], QueryObserverResult\<InferDataAndError\<(...)\[(...)\]\>\["data"\], InferDataAndError\<(...)\[(...)\]\>\["error"\]\>, DefinedQueryObserverResult\<InferDataAndError\<(...)\[(...)\]\>\["data"\], InferDataAndError\<(...)\[(...)\]\>\["error"\]\>\> \}
+
+#### Returns
+
+`TCombinedResult`
+
+***
+
+### queries
+
+```ts
+queries: 
+  | readonly [{ [K in string | number | symbol]: GetCreateQueryOptionsForCreateQueries<T[K<K>]> }]
+  | readonly [T extends [] ? [] : T extends [Head] ? [GetCreateQueryOptionsForCreateQueries<Head>] : T extends [Head, ...Tails[]] ? [...Tails[]] extends [] ? [] : [...Tails[]] extends [Head] ? [GetCreateQueryOptionsForCreateQueries<Head>, GetCreateQueryOptionsForCreateQueries<Head>] : [...Tails[]] extends [Head, ...Tails[]] ? [...Tails[]] extends [] ? [] : [...(...)[]] extends [...] ? [..., ..., ...] : ... extends ... ? ... : ... : readonly unknown[] extends [...Tails[]] ? [...Tails[]] : [...(...)[]] extends ...[] ? ...[] : ...[] : readonly unknown[] extends T ? T : T extends QueryObserverOptionsForCreateQueries<TQueryFnData, TError, TData, TQueryKey>[] ? QueryObserverOptionsForCreateQueries<TQueryFnData, TError, TData, TQueryKey>[] : QueryObserverOptionsForCreateQueries<unknown, Error, unknown, readonly unknown[]>[]];
+```
+
+Defined in: [inject-queries.ts:261](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-queries.ts#L261)
diff --git a/docs/framework/angular/reference/interfaces/InjectQueryOptions.md b/docs/framework/angular/reference/interfaces/InjectQueryOptions.md
index eecbef2804..8f513c31b5 100644
--- a/docs/framework/angular/reference/interfaces/InjectQueryOptions.md
+++ b/docs/framework/angular/reference/interfaces/InjectQueryOptions.md
@@ -5,7 +5,7 @@ title: InjectQueryOptions
 
 # Interface: InjectQueryOptions
 
-Defined in: [inject-query.ts:20](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-query.ts#L20)
+Defined in: [inject-query.ts:25](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-query.ts#L25)
 
 ## Properties
 
@@ -15,7 +15,7 @@ Defined in: [inject-query.ts:20](https://github.com/TanStack/query/blob/main/pac
 optional injector: Injector;
 ```
 
-Defined in: [inject-query.ts:26](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-query.ts#L26)
+Defined in: [inject-query.ts:31](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-query.ts#L31)
 
 The `Injector` in which to create the query.
 
diff --git a/docs/framework/angular/reference/interfaces/CreateBaseQueryOptions.md b/docs/framework/angular/reference/type-aliases/CreateBaseQueryOptions.md
similarity index 63%
rename from docs/framework/angular/reference/interfaces/CreateBaseQueryOptions.md
rename to docs/framework/angular/reference/type-aliases/CreateBaseQueryOptions.md
index 48a4b7dcc6..29bacc3ac0 100644
--- a/docs/framework/angular/reference/interfaces/CreateBaseQueryOptions.md
+++ b/docs/framework/angular/reference/type-aliases/CreateBaseQueryOptions.md
@@ -3,13 +3,13 @@ id: CreateBaseQueryOptions
 title: CreateBaseQueryOptions
 ---
 
-# Interface: CreateBaseQueryOptions\<TQueryFnData, TError, TData, TQueryData, TQueryKey\>
+# Type Alias: CreateBaseQueryOptions\<TQueryFnData, TError, TData, TQueryData, TQueryKey\>
 
-Defined in: [types.ts:21](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L21)
-
-## Extends
+```ts
+type CreateBaseQueryOptions<TQueryFnData, TError, TData, TQueryData, TQueryKey> = QueryObserverOptions<TQueryFnData, TError, TData, TQueryData, TQueryKey>;
+```
 
-- `QueryObserverOptions`\<`TQueryFnData`, `TError`, `TData`, `TQueryData`, `TQueryKey`\>
+Defined in: [types.ts:21](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L21)
 
 ## Type Parameters
 
diff --git a/docs/framework/angular/reference/type-aliases/CreateBaseQueryResult.md b/docs/framework/angular/reference/type-aliases/CreateBaseQueryResult.md
index 784f89c5e1..0ed7f2524b 100644
--- a/docs/framework/angular/reference/type-aliases/CreateBaseQueryResult.md
+++ b/docs/framework/angular/reference/type-aliases/CreateBaseQueryResult.md
@@ -6,10 +6,10 @@ title: CreateBaseQueryResult
 # Type Alias: CreateBaseQueryResult\<TData, TError, TState\>
 
 ```ts
-type CreateBaseQueryResult<TData, TError, TState> = BaseQueryNarrowing<TData, TError> & MapToSignals<OmitKeyof<TState, keyof BaseQueryNarrowing, "safely">>;
+type CreateBaseQueryResult<TData, TError, TState> = BaseQueryNarrowing<TData, TError> & MapToSignals<OmitKeyof<TState, keyof BaseQueryNarrowing, "safely">, MethodKeys<OmitKeyof<TState, keyof BaseQueryNarrowing, "safely">>>;
 ```
 
-Defined in: [types.ts:98](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L98)
+Defined in: [types.ts:86](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L86)
 
 ## Type Parameters
 
diff --git a/docs/framework/angular/reference/type-aliases/CreateInfiniteQueryResult.md b/docs/framework/angular/reference/type-aliases/CreateInfiniteQueryResult.md
index f4c01a674b..fc9a51d4b0 100644
--- a/docs/framework/angular/reference/type-aliases/CreateInfiniteQueryResult.md
+++ b/docs/framework/angular/reference/type-aliases/CreateInfiniteQueryResult.md
@@ -6,10 +6,10 @@ title: CreateInfiniteQueryResult
 # Type Alias: CreateInfiniteQueryResult\<TData, TError\>
 
 ```ts
-type CreateInfiniteQueryResult<TData, TError> = BaseQueryNarrowing<TData, TError> & MapToSignals<InfiniteQueryObserverResult<TData, TError>>;
+type CreateInfiniteQueryResult<TData, TError> = BaseQueryNarrowing<TData, TError> & MapToSignals<InfiniteQueryObserverResult<TData, TError>, MethodKeys<InfiniteQueryObserverResult<TData, TError>>>;
 ```
 
-Defined in: [types.ts:117](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L117)
+Defined in: [types.ts:111](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L111)
 
 ## Type Parameters
 
diff --git a/docs/framework/angular/reference/type-aliases/CreateMutationResult.md b/docs/framework/angular/reference/type-aliases/CreateMutationResult.md
index b5573544d0..86c2056181 100644
--- a/docs/framework/angular/reference/type-aliases/CreateMutationResult.md
+++ b/docs/framework/angular/reference/type-aliases/CreateMutationResult.md
@@ -6,7 +6,7 @@ title: CreateMutationResult
 # Type Alias: CreateMutationResult\<TData, TError, TVariables, TOnMutateResult, TState\>
 
 ```ts
-type CreateMutationResult<TData, TError, TVariables, TOnMutateResult, TState> = BaseMutationNarrowing<TData, TError, TVariables, TOnMutateResult> & MapToSignals<OmitKeyof<TState, keyof BaseMutationNarrowing, "safely">>;
+type CreateMutationResult<TData, TError, TVariables, TOnMutateResult, TState> = BaseMutationNarrowing<TData, TError, TVariables, TOnMutateResult> & MapToSignals<OmitKeyof<TState, keyof BaseMutationNarrowing, "safely">, MethodKeys<OmitKeyof<TState, keyof BaseMutationNarrowing, "safely">>>;
 ```
 
 Defined in: [types.ts:266](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L266)
diff --git a/docs/framework/angular/reference/type-aliases/CreateQueryOptions.md b/docs/framework/angular/reference/type-aliases/CreateQueryOptions.md
new file mode 100644
index 0000000000..799c2d3b11
--- /dev/null
+++ b/docs/framework/angular/reference/type-aliases/CreateQueryOptions.md
@@ -0,0 +1,30 @@
+---
+id: CreateQueryOptions
+title: CreateQueryOptions
+---
+
+# Type Alias: CreateQueryOptions\<TQueryFnData, TError, TData, TQueryKey\>
+
+```ts
+type CreateQueryOptions<TQueryFnData, TError, TData, TQueryKey> = OmitKeyof<CreateBaseQueryOptions<TQueryFnData, TError, TData, TQueryFnData, TQueryKey>, "suspense">;
+```
+
+Defined in: [types.ts:29](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L29)
+
+## Type Parameters
+
+### TQueryFnData
+
+`TQueryFnData` = `unknown`
+
+### TError
+
+`TError` = `DefaultError`
+
+### TData
+
+`TData` = `TQueryFnData`
+
+### TQueryKey
+
+`TQueryKey` *extends* `QueryKey` = `QueryKey`
diff --git a/docs/framework/angular/reference/type-aliases/CreateQueryResult.md b/docs/framework/angular/reference/type-aliases/CreateQueryResult.md
index c532a87463..67d2f6cd86 100644
--- a/docs/framework/angular/reference/type-aliases/CreateQueryResult.md
+++ b/docs/framework/angular/reference/type-aliases/CreateQueryResult.md
@@ -9,7 +9,7 @@ title: CreateQueryResult
 type CreateQueryResult<TData, TError> = CreateBaseQueryResult<TData, TError>;
 ```
 
-Defined in: [types.ts:105](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L105)
+Defined in: [types.ts:96](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L96)
 
 ## Type Parameters
 
diff --git a/docs/framework/angular/reference/type-aliases/DefinedCreateInfiniteQueryResult.md b/docs/framework/angular/reference/type-aliases/DefinedCreateInfiniteQueryResult.md
index 932114c7d1..6760031992 100644
--- a/docs/framework/angular/reference/type-aliases/DefinedCreateInfiniteQueryResult.md
+++ b/docs/framework/angular/reference/type-aliases/DefinedCreateInfiniteQueryResult.md
@@ -6,10 +6,10 @@ title: DefinedCreateInfiniteQueryResult
 # Type Alias: DefinedCreateInfiniteQueryResult\<TData, TError, TDefinedInfiniteQueryObserver\>
 
 ```ts
-type DefinedCreateInfiniteQueryResult<TData, TError, TDefinedInfiniteQueryObserver> = MapToSignals<TDefinedInfiniteQueryObserver>;
+type DefinedCreateInfiniteQueryResult<TData, TError, TDefinedInfiniteQueryObserver> = MapToSignals<TDefinedInfiniteQueryObserver, MethodKeys<TDefinedInfiniteQueryObserver>>;
 ```
 
-Defined in: [types.ts:123](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L123)
+Defined in: [types.ts:120](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L120)
 
 ## Type Parameters
 
diff --git a/docs/framework/angular/reference/type-aliases/DefinedCreateQueryResult.md b/docs/framework/angular/reference/type-aliases/DefinedCreateQueryResult.md
index 60fa877491..9ef090ccf8 100644
--- a/docs/framework/angular/reference/type-aliases/DefinedCreateQueryResult.md
+++ b/docs/framework/angular/reference/type-aliases/DefinedCreateQueryResult.md
@@ -6,10 +6,10 @@ title: DefinedCreateQueryResult
 # Type Alias: DefinedCreateQueryResult\<TData, TError, TState\>
 
 ```ts
-type DefinedCreateQueryResult<TData, TError, TState> = BaseQueryNarrowing<TData, TError> & MapToSignals<OmitKeyof<TState, keyof BaseQueryNarrowing, "safely">>;
+type DefinedCreateQueryResult<TData, TError, TState> = BaseQueryNarrowing<TData, TError> & MapToSignals<OmitKeyof<TState, keyof BaseQueryNarrowing, "safely">, MethodKeys<OmitKeyof<TState, keyof BaseQueryNarrowing, "safely">>>;
 ```
 
-Defined in: [types.ts:110](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L110)
+Defined in: [types.ts:101](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L101)
 
 ## Type Parameters
 
diff --git a/docs/framework/angular/reference/type-aliases/DefinedInitialDataOptions.md b/docs/framework/angular/reference/type-aliases/DefinedInitialDataOptions.md
index 4bcea1da72..4c8ad5c0ab 100644
--- a/docs/framework/angular/reference/type-aliases/DefinedInitialDataOptions.md
+++ b/docs/framework/angular/reference/type-aliases/DefinedInitialDataOptions.md
@@ -6,10 +6,10 @@ title: DefinedInitialDataOptions
 # Type Alias: DefinedInitialDataOptions\<TQueryFnData, TError, TData, TQueryKey\>
 
 ```ts
-type DefinedInitialDataOptions<TQueryFnData, TError, TData, TQueryKey> = Omit<CreateQueryOptions<TQueryFnData, TError, TData, TQueryKey>, "queryFn"> & object;
+type DefinedInitialDataOptions<TQueryFnData, TError, TData, TQueryKey> = CreateQueryOptions<TQueryFnData, TError, TData, TQueryKey> & object;
 ```
 
-Defined in: [query-options.ts:40](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/query-options.ts#L40)
+Defined in: [query-options.ts:39](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/query-options.ts#L39)
 
 ## Type Declaration
 
@@ -21,12 +21,6 @@ initialData:
 | () => NonUndefinedGuard<TQueryFnData>;
 ```
 
-### queryFn?
-
-```ts
-optional queryFn: QueryFunction<TQueryFnData, TQueryKey>;
-```
-
 ## Type Parameters
 
 ### TQueryFnData
diff --git a/docs/framework/angular/reference/type-aliases/QueriesOptions.md b/docs/framework/angular/reference/type-aliases/QueriesOptions.md
index 2def13c9c9..c8f95bb1a7 100644
--- a/docs/framework/angular/reference/type-aliases/QueriesOptions.md
+++ b/docs/framework/angular/reference/type-aliases/QueriesOptions.md
@@ -9,7 +9,7 @@ title: QueriesOptions
 type QueriesOptions<T, TResults, TDepth> = TDepth["length"] extends MAXIMUM_DEPTH ? QueryObserverOptionsForCreateQueries[] : T extends [] ? [] : T extends [infer Head] ? [...TResults, GetCreateQueryOptionsForCreateQueries<Head>] : T extends [infer Head, ...(infer Tails)] ? QueriesOptions<[...Tails], [...TResults, GetCreateQueryOptionsForCreateQueries<Head>], [...TDepth, 1]> : ReadonlyArray<unknown> extends T ? T : T extends QueryObserverOptionsForCreateQueries<infer TQueryFnData, infer TError, infer TData, infer TQueryKey>[] ? QueryObserverOptionsForCreateQueries<TQueryFnData, TError, TData, TQueryKey>[] : QueryObserverOptionsForCreateQueries[];
 ```
 
-Defined in: [inject-queries.ts:144](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-queries.ts#L144)
+Defined in: [inject-queries.ts:178](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-queries.ts#L178)
 
 QueriesOptions reducer recursively unwraps function arguments to infer/enforce type param
 
diff --git a/docs/framework/angular/reference/type-aliases/QueriesResults.md b/docs/framework/angular/reference/type-aliases/QueriesResults.md
index 6d5ecf6dd4..b34b39cb60 100644
--- a/docs/framework/angular/reference/type-aliases/QueriesResults.md
+++ b/docs/framework/angular/reference/type-aliases/QueriesResults.md
@@ -9,7 +9,7 @@ title: QueriesResults
 type QueriesResults<T, TResults, TDepth> = TDepth["length"] extends MAXIMUM_DEPTH ? CreateQueryResult[] : T extends [] ? [] : T extends [infer Head] ? [...TResults, GetCreateQueryResult<Head>] : T extends [infer Head, ...(infer Tails)] ? QueriesResults<[...Tails], [...TResults, GetCreateQueryResult<Head>], [...TDepth, 1]> : { [K in keyof T]: GetCreateQueryResult<T[K]> };
 ```
 
-Defined in: [inject-queries.ts:186](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-queries.ts#L186)
+Defined in: [inject-queries.ts:220](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-queries.ts#L220)
 
 QueriesResults reducer recursively maps type param to results
 
diff --git a/docs/framework/angular/reference/type-aliases/UndefinedInitialDataOptions.md b/docs/framework/angular/reference/type-aliases/UndefinedInitialDataOptions.md
index f1a48e74e6..339c1e5684 100644
--- a/docs/framework/angular/reference/type-aliases/UndefinedInitialDataOptions.md
+++ b/docs/framework/angular/reference/type-aliases/UndefinedInitialDataOptions.md
@@ -9,7 +9,7 @@ title: UndefinedInitialDataOptions
 type UndefinedInitialDataOptions<TQueryFnData, TError, TData, TQueryKey> = CreateQueryOptions<TQueryFnData, TError, TData, TQueryKey> & object;
 ```
 
-Defined in: [query-options.ts:13](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/query-options.ts#L13)
+Defined in: [query-options.ts:12](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/query-options.ts#L12)
 
 ## Type Declaration
 
diff --git a/docs/framework/angular/reference/type-aliases/UnusedSkipTokenOptions.md b/docs/framework/angular/reference/type-aliases/UnusedSkipTokenOptions.md
index 9a65d5b3f3..bebe298be7 100644
--- a/docs/framework/angular/reference/type-aliases/UnusedSkipTokenOptions.md
+++ b/docs/framework/angular/reference/type-aliases/UnusedSkipTokenOptions.md
@@ -9,7 +9,7 @@ title: UnusedSkipTokenOptions
 type UnusedSkipTokenOptions<TQueryFnData, TError, TData, TQueryKey> = OmitKeyof<CreateQueryOptions<TQueryFnData, TError, TData, TQueryKey>, "queryFn"> & object;
 ```
 
-Defined in: [query-options.ts:25](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/query-options.ts#L25)
+Defined in: [query-options.ts:24](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/query-options.ts#L24)
 
 ## Type Declaration
 
diff --git a/docs/framework/angular/typescript.md b/docs/framework/angular/typescript.md
index 0aa2ff2638..0dea29de35 100644
--- a/docs/framework/angular/typescript.md
+++ b/docs/framework/angular/typescript.md
@@ -12,6 +12,7 @@ replace:
     'React Query': 'TanStack Query',
     '`success`': '`isSuccess()`',
     'function:': 'function.',
+    'separate function': 'separate function or a service',
   }
 ---
 
@@ -52,7 +53,7 @@ class MyComponent {
 [//]: # 'TypeInference2'
 [//]: # 'TypeInference3'
 
-In this example we pass Group[] to the type parameter of HttpClient's `get` method.
+In this example we pass `Group[]` to the type parameter of HttpClient's `get` method.
 
 ```angular-ts
 @Component({
@@ -70,6 +71,7 @@ class MyComponent {
 ```
 
 [//]: # 'TypeInference3'
+[//]: # 'TypeInference4'
 [//]: # 'TypeNarrowing'
 
 ```angular-ts
@@ -90,8 +92,9 @@ class MyComponent {
 }
 ```
 
-> TypeScript currently does not support discriminated unions on object methods. Narrowing on signal fields on objects such as query results only works on signals returning a boolean. Prefer using `isSuccess()` and similar boolean status signals over `status() === 'success'`.
+> TypeScript currently does not support discriminated unions on object methods. Narrowing on signal fields on objects such as query results only works on signals returning a boolean. Prefer using `isSuccess()`, `isError()` and `isPending()` over `status() === 'success'`.
 
+[//]: # 'TypeInference4'
 [//]: # 'TypeNarrowing'
 [//]: # 'TypingError'
 
@@ -153,8 +156,7 @@ import '@tanstack/angular-query-experimental'
 
 declare module '@tanstack/angular-query-experimental' {
   interface Register {
-    // Use unknown so call sites must narrow explicitly.
-    defaultError: unknown
+    defaultError: AxiosError
   }
 }
 
@@ -165,7 +167,7 @@ const query = injectQuery(() => ({
 
 computed(() => {
   const error = query.error()
-  //      ^? error: unknown | null
+  //      ^? error: AxiosError | null
 })
 ```
 
diff --git a/examples/angular/infinite-query-with-max-pages/src/app/components/example.component.ts b/examples/angular/infinite-query-with-max-pages/src/app/components/example.component.ts
index 71c141e3e4..3232f64942 100644
--- a/examples/angular/infinite-query-with-max-pages/src/app/components/example.component.ts
+++ b/examples/angular/infinite-query-with-max-pages/src/app/components/example.component.ts
@@ -30,30 +30,25 @@ export class ExampleComponent {
   }))
 
   readonly nextButtonDisabled = computed(
-    () => !this.#hasNextPage() || this.#isFetchingNextPage(),
+    () => !this.query.hasNextPage() || this.query.isFetchingNextPage(),
   )
 
   readonly nextButtonText = computed(() =>
-    this.#isFetchingNextPage()
+    this.query.isFetchingNextPage()
       ? 'Loading more...'
-      : this.#hasNextPage()
+      : this.query.hasNextPage()
         ? 'Load newer'
         : 'Nothing more to load',
   )
 
   readonly previousButtonDisabled = computed(
-    () => !this.#hasPreviousPage() || this.#isFetchingNextPage(),
+    () => !this.query.hasPreviousPage() || this.query.isFetchingPreviousPage(),
   )
   readonly previousButtonText = computed(() =>
-    this.#isFetchingPreviousPage()
+    this.query.isFetchingPreviousPage()
       ? 'Loading more...'
-      : this.#hasPreviousPage()
+      : this.query.hasPreviousPage()
         ? 'Load Older'
         : 'Nothing more to load',
   )
-
-  readonly #hasPreviousPage = this.query.hasPreviousPage
-  readonly #hasNextPage = this.query.hasNextPage
-  readonly #isFetchingPreviousPage = this.query.isFetchingPreviousPage
-  readonly #isFetchingNextPage = this.query.isFetchingNextPage
 }
diff --git a/examples/angular/optimistic-updates/src/app/components/optimistic-updates.component.ts b/examples/angular/optimistic-updates/src/app/components/optimistic-updates.component.ts
index 2b0b4cc1c4..b32a0f50dc 100644
--- a/examples/angular/optimistic-updates/src/app/components/optimistic-updates.component.ts
+++ b/examples/angular/optimistic-updates/src/app/components/optimistic-updates.component.ts
@@ -36,7 +36,7 @@ import { TasksService } from '../services/tasks.service'
         <input type="text" [(ngModel)]="newItem" placeholder="Enter text" />
         <button (click)="addItem()">Create</button>
         <ul>
-          @for (task of tasks.data(); track task) {
+          @for (task of tasks.data(); track $index) {
             <li>{{ task }}</li>
           }
         </ul>
diff --git a/packages/angular-query-experimental/README.md b/packages/angular-query-experimental/README.md
index 6ed2dfa05a..7a60650d6d 100644
--- a/packages/angular-query-experimental/README.md
+++ b/packages/angular-query-experimental/README.md
@@ -29,7 +29,7 @@ Visit https://tanstack.com/query/latest/docs/framework/angular/overview
 
 # Quick Start
 
-> The Angular adapter for TanStack Query requires Angular 16 or higher.
+> The Angular adapter for TanStack Query requires Angular 19 or higher.
 
 1. Install `angular-query`
 
@@ -78,9 +78,10 @@ import {
 @NgModule({
   declarations: [AppComponent],
   imports: [BrowserModule],
-  providers: [provideTanStackQuery(new QueryClient())],
+  providers: [provideTanStackQuery(new QueryClient()), provideHttpClient()],
   bootstrap: [AppComponent],
 })
+export class AppModule {}
 ```
 
 3. Inject query
diff --git a/packages/angular-query-experimental/package.json b/packages/angular-query-experimental/package.json
index 594ac9840a..11afc14ac4 100644
--- a/packages/angular-query-experimental/package.json
+++ b/packages/angular-query-experimental/package.json
@@ -31,11 +31,6 @@
     "compile": "tsc --build",
     "test:eslint": "eslint --concurrency=auto ./src",
     "test:types": "npm-run-all --serial test:types:*",
-    "test:types:ts50": "node ../../node_modules/typescript50/lib/tsc.js --build",
-    "test:types:ts51": "node ../../node_modules/typescript51/lib/tsc.js --build",
-    "test:types:ts52": "node ../../node_modules/typescript52/lib/tsc.js --build",
-    "test:types:ts53": "node ../../node_modules/typescript53/lib/tsc.js --build",
-    "test:types:ts54": "node ../../node_modules/typescript54/lib/tsc.js --build",
     "test:types:ts55": "node ../../node_modules/typescript55/lib/tsc.js --build",
     "test:types:ts56": "node ../../node_modules/typescript56/lib/tsc.js --build",
     "test:types:ts57": "node ../../node_modules/typescript57/lib/tsc.js --build",
@@ -93,20 +88,22 @@
     "@angular/compiler": "^20.0.0",
     "@angular/core": "^20.0.0",
     "@angular/platform-browser": "^20.0.0",
+    "@angular/platform-server": "^20.0.0",
     "@tanstack/query-test-utils": "workspace:*",
     "@testing-library/angular": "^18.0.0",
     "npm-run-all2": "^5.0.0",
     "rxjs": "^7.8.2",
     "vite-plugin-dts": "4.2.3",
     "vite-plugin-externalize-deps": "^0.9.0",
-    "vite-tsconfig-paths": "^5.1.4"
+    "vite-tsconfig-paths": "^5.1.4",
+    "zone.js": "^0.16.0"
   },
   "optionalDependencies": {
     "@tanstack/query-devtools": "workspace:*"
   },
   "peerDependencies": {
-    "@angular/common": ">=16.0.0",
-    "@angular/core": ">=16.0.0"
+    "@angular/common": ">=19.0.0",
+    "@angular/core": ">=19.0.0"
   },
   "publishConfig": {
     "directory": "dist",
diff --git a/packages/angular-query-experimental/src/__tests__/inject-devtools-panel.test.ts b/packages/angular-query-experimental/src/__tests__/inject-devtools-panel.test.ts
index 3a1fc4bca8..048e063b40 100644
--- a/packages/angular-query-experimental/src/__tests__/inject-devtools-panel.test.ts
+++ b/packages/angular-query-experimental/src/__tests__/inject-devtools-panel.test.ts
@@ -1,13 +1,9 @@
-import {
-  ElementRef,
-  provideZonelessChangeDetection,
-  signal,
-} from '@angular/core'
+import { ElementRef, signal } from '@angular/core'
 import { TestBed } from '@angular/core/testing'
 import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
 import { QueryClient } from '@tanstack/query-core'
-import { provideTanStackQuery } from '../providers'
 import { injectDevtoolsPanel } from '../devtools-panel'
+import { setupTanStackQueryTestBed } from './test-utils'
 
 const mockDevtoolsPanelInstance = {
   mount: vi.fn(),
@@ -45,12 +41,8 @@ describe('injectDevtoolsPanel', () => {
     vi.clearAllMocks()
     queryClient = new QueryClient()
     mockElementRef = new ElementRef(document.createElement('div'))
-    TestBed.configureTestingModule({
-      providers: [
-        provideZonelessChangeDetection(),
-        provideTanStackQuery(queryClient),
-        { provide: ElementRef, useValue: signal(mockElementRef) },
-      ],
+    setupTanStackQueryTestBed(queryClient, {
+      providers: [{ provide: ElementRef, useValue: signal(mockElementRef) }],
     })
   })
 
diff --git a/packages/angular-query-experimental/src/__tests__/inject-infinite-query.test-d.ts b/packages/angular-query-experimental/src/__tests__/inject-infinite-query.test-d.ts
index 7ec133adfb..c34c580ddc 100644
--- a/packages/angular-query-experimental/src/__tests__/inject-infinite-query.test-d.ts
+++ b/packages/angular-query-experimental/src/__tests__/inject-infinite-query.test-d.ts
@@ -1,42 +1,97 @@
-import { TestBed } from '@angular/core/testing'
-import { afterEach, beforeEach, describe, expectTypeOf, test, vi } from 'vitest'
-import { provideZonelessChangeDetection } from '@angular/core'
-import { sleep } from '@tanstack/query-test-utils'
-import { QueryClient, injectInfiniteQuery, provideTanStackQuery } from '..'
+import { describe, expectTypeOf, it, test } from 'vitest'
+import { injectInfiniteQuery } from '..'
+import type { Signal } from '@angular/core'
 import type { InfiniteData } from '@tanstack/query-core'
 
 describe('injectInfiniteQuery', () => {
-  let queryClient: QueryClient
-
-  beforeEach(() => {
-    queryClient = new QueryClient()
-    vi.useFakeTimers()
-    TestBed.configureTestingModule({
-      providers: [
-        provideZonelessChangeDetection(),
-        provideTanStackQuery(queryClient),
-      ],
+  describe('Discriminated union return type', () => {
+    test('data should be possibly undefined by default', () => {
+      const query = injectInfiniteQuery(() => ({
+        queryKey: ['infiniteQuery'],
+        queryFn: ({ pageParam }) =>
+          Promise.resolve('data on page ' + pageParam),
+        initialPageParam: 0,
+        getNextPageParam: () => 12,
+      }))
+
+      expectTypeOf(query.data).toEqualTypeOf<
+        Signal<undefined> | Signal<InfiniteData<string, unknown>>
+      >()
     })
-  })
 
-  afterEach(() => {
-    vi.useRealTimers()
-  })
+    test('data should be defined when query is success', () => {
+      const query = injectInfiniteQuery(() => ({
+        queryKey: ['infiniteQuery'],
+        queryFn: ({ pageParam }) =>
+          Promise.resolve('data on page ' + pageParam),
+        initialPageParam: 0,
+        getNextPageParam: () => 12,
+      }))
+
+      if (query.isSuccess()) {
+        expectTypeOf(query.data).toEqualTypeOf<
+          Signal<InfiniteData<string, unknown>>
+        >()
+      }
+    })
+
+    test('error should be null when query is success', () => {
+      const query = injectInfiniteQuery(() => ({
+        queryKey: ['infiniteQuery'],
+        queryFn: ({ pageParam }) =>
+          Promise.resolve('data on page ' + pageParam),
+        initialPageParam: 0,
+        getNextPageParam: () => 12,
+      }))
 
-  test('should narrow type after isSuccess', () => {
-    const query = TestBed.runInInjectionContext(() => {
-      return injectInfiniteQuery(() => ({
+      if (query.isSuccess()) {
+        expectTypeOf(query.error).toEqualTypeOf<Signal<null>>()
+      }
+    })
+
+    test('data should be undefined when query is pending', () => {
+      const query = injectInfiniteQuery(() => ({
         queryKey: ['infiniteQuery'],
         queryFn: ({ pageParam }) =>
-          sleep(0).then(() => 'data on page ' + pageParam),
+          Promise.resolve('data on page ' + pageParam),
         initialPageParam: 0,
         getNextPageParam: () => 12,
       }))
+
+      if (query.isPending()) {
+        expectTypeOf(query.data).toEqualTypeOf<Signal<undefined>>()
+      }
     })
 
-    if (query.isSuccess()) {
-      const data = query.data()
-      expectTypeOf(data).toEqualTypeOf<InfiniteData<string, unknown>>()
-    }
+    test('error should be defined when query is error', () => {
+      const query = injectInfiniteQuery(() => ({
+        queryKey: ['infiniteQuery'],
+        queryFn: ({ pageParam }) =>
+          Promise.resolve('data on page ' + pageParam),
+        initialPageParam: 0,
+        getNextPageParam: () => 12,
+      }))
+
+      if (query.isError()) {
+        expectTypeOf(query.error).toEqualTypeOf<Signal<Error>>()
+      }
+    })
+  })
+
+  it('should provide the correct types to the select function', () => {
+    const query = injectInfiniteQuery(() => ({
+      queryKey: ['infiniteQuery'],
+      queryFn: ({ pageParam }) => Promise.resolve('data on page ' + pageParam),
+      initialPageParam: 0,
+      getNextPageParam: () => 12,
+      select: (data) => {
+        expectTypeOf(data).toEqualTypeOf<InfiniteData<string, number>>()
+        return data
+      },
+    }))
+
+    expectTypeOf(query.data).toEqualTypeOf<
+      Signal<undefined> | Signal<InfiniteData<string, number>>
+    >()
   })
 })
diff --git a/packages/angular-query-experimental/src/__tests__/inject-infinite-query.test.ts b/packages/angular-query-experimental/src/__tests__/inject-infinite-query.test.ts
index 7873d5261c..f587f6a2fe 100644
--- a/packages/angular-query-experimental/src/__tests__/inject-infinite-query.test.ts
+++ b/packages/angular-query-experimental/src/__tests__/inject-infinite-query.test.ts
@@ -1,9 +1,9 @@
 import { TestBed } from '@angular/core/testing'
 import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'
-import { Injector, provideZonelessChangeDetection } from '@angular/core'
+import { ChangeDetectionStrategy, Component, Injector } from '@angular/core'
 import { sleep } from '@tanstack/query-test-utils'
-import { QueryClient, injectInfiniteQuery, provideTanStackQuery } from '..'
-import { expectSignals } from './test-utils'
+import { QueryClient, injectInfiniteQuery } from '..'
+import { expectSignals, setupTanStackQueryTestBed } from './test-utils'
 
 describe('injectInfiniteQuery', () => {
   let queryClient: QueryClient
@@ -11,12 +11,7 @@ describe('injectInfiniteQuery', () => {
   beforeEach(() => {
     queryClient = new QueryClient()
     vi.useFakeTimers()
-    TestBed.configureTestingModule({
-      providers: [
-        provideZonelessChangeDetection(),
-        provideTanStackQuery(queryClient),
-      ],
-    })
+    setupTanStackQueryTestBed(queryClient)
   })
 
   afterEach(() => {
@@ -24,15 +19,24 @@ describe('injectInfiniteQuery', () => {
   })
 
   test('should properly execute infinite query', async () => {
-    const query = TestBed.runInInjectionContext(() => {
-      return injectInfiniteQuery(() => ({
+    @Component({
+      selector: 'app-test',
+      template: '',
+      changeDetection: ChangeDetectionStrategy.OnPush,
+    })
+    class TestComponent {
+      query = injectInfiniteQuery(() => ({
         queryKey: ['infiniteQuery'],
         queryFn: ({ pageParam }) =>
           sleep(10).then(() => 'data on page ' + pageParam),
         initialPageParam: 0,
         getNextPageParam: () => 12,
       }))
-    })
+    }
+
+    const fixture = TestBed.createComponent(TestComponent)
+    fixture.detectChanges()
+    const query = fixture.componentInstance.query
 
     expectSignals(query, {
       data: undefined,
@@ -76,6 +80,9 @@ describe('injectInfiniteQuery', () => {
     })
 
     test('can be used outside injection context when passing an injector', () => {
+      const injector = TestBed.inject(Injector)
+
+      // Call injectInfiniteQuery directly outside any component
       const query = injectInfiniteQuery(
         () => ({
           queryKey: ['manualInjector'],
@@ -85,10 +92,12 @@ describe('injectInfiniteQuery', () => {
           getNextPageParam: () => 12,
         }),
         {
-          injector: TestBed.inject(Injector),
+          injector: injector,
         },
       )
 
+      TestBed.tick()
+
       expect(query.status()).toBe('pending')
     })
   })
diff --git a/packages/angular-query-experimental/src/__tests__/inject-is-fetching.test.ts b/packages/angular-query-experimental/src/__tests__/inject-is-fetching.test.ts
index 329ef6d9e3..a7461dbc26 100644
--- a/packages/angular-query-experimental/src/__tests__/inject-is-fetching.test.ts
+++ b/packages/angular-query-experimental/src/__tests__/inject-is-fetching.test.ts
@@ -1,13 +1,9 @@
 import { TestBed } from '@angular/core/testing'
 import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'
-import { Injector, provideZonelessChangeDetection } from '@angular/core'
+import { Injector } from '@angular/core'
 import { sleep } from '@tanstack/query-test-utils'
-import {
-  QueryClient,
-  injectIsFetching,
-  injectQuery,
-  provideTanStackQuery,
-} from '..'
+import { QueryClient, injectIsFetching, injectQuery } from '..'
+import { setupTanStackQueryTestBed } from './test-utils'
 
 describe('injectIsFetching', () => {
   let queryClient: QueryClient
@@ -16,12 +12,7 @@ describe('injectIsFetching', () => {
     vi.useFakeTimers()
     queryClient = new QueryClient()
 
-    TestBed.configureTestingModule({
-      providers: [
-        provideZonelessChangeDetection(),
-        provideTanStackQuery(queryClient),
-      ],
-    })
+    setupTanStackQueryTestBed(queryClient)
   })
 
   afterEach(() => {
diff --git a/packages/angular-query-experimental/src/__tests__/inject-is-mutating.test.ts b/packages/angular-query-experimental/src/__tests__/inject-is-mutating.test.ts
index 5a4694cb85..6d30b988f4 100644
--- a/packages/angular-query-experimental/src/__tests__/inject-is-mutating.test.ts
+++ b/packages/angular-query-experimental/src/__tests__/inject-is-mutating.test.ts
@@ -1,13 +1,9 @@
 import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'
 import { TestBed } from '@angular/core/testing'
-import { Injector, provideZonelessChangeDetection } from '@angular/core'
+import { Injector } from '@angular/core'
 import { sleep } from '@tanstack/query-test-utils'
-import {
-  QueryClient,
-  injectIsMutating,
-  injectMutation,
-  provideTanStackQuery,
-} from '..'
+import { QueryClient, injectIsMutating, injectMutation } from '..'
+import { flushQueryUpdates, setupTanStackQueryTestBed } from './test-utils'
 
 describe('injectIsMutating', () => {
   let queryClient: QueryClient
@@ -16,12 +12,7 @@ describe('injectIsMutating', () => {
     vi.useFakeTimers()
     queryClient = new QueryClient()
 
-    TestBed.configureTestingModule({
-      providers: [
-        provideZonelessChangeDetection(),
-        provideTanStackQuery(queryClient),
-      ],
-    })
+    setupTanStackQueryTestBed(queryClient)
   })
 
   afterEach(() => {
@@ -44,7 +35,7 @@ describe('injectIsMutating', () => {
     })
 
     expect(isMutating()).toBe(0)
-    await vi.advanceTimersByTimeAsync(0)
+    await flushQueryUpdates()
     expect(isMutating()).toBe(1)
     await vi.advanceTimersByTimeAsync(11)
     expect(isMutating()).toBe(0)
diff --git a/packages/angular-query-experimental/src/__tests__/inject-mutation-state.test.ts b/packages/angular-query-experimental/src/__tests__/inject-mutation-state.test.ts
index 8b747f66f6..e8c86c068f 100644
--- a/packages/angular-query-experimental/src/__tests__/inject-mutation-state.test.ts
+++ b/packages/angular-query-experimental/src/__tests__/inject-mutation-state.test.ts
@@ -1,4 +1,5 @@
 import {
+  ChangeDetectionStrategy,
   Component,
   Injector,
   input,
@@ -7,7 +8,6 @@ import {
 } from '@angular/core'
 import { TestBed } from '@angular/core/testing'
 import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'
-import { By } from '@angular/platform-browser'
 import { sleep } from '@tanstack/query-test-utils'
 import {
   QueryClient,
@@ -15,7 +15,7 @@ import {
   injectMutationState,
   provideTanStackQuery,
 } from '..'
-import { setFixtureSignalInputs } from './test-utils'
+import { registerSignalInput } from './test-utils'
 
 describe('injectMutationState', () => {
   let queryClient: QueryClient
@@ -145,6 +145,7 @@ describe('injectMutationState', () => {
             <span>{{ mutation.status }}</span>
           }
         `,
+        changeDetection: ChangeDetectionStrategy.OnPush,
       })
       class FakeComponent {
         name = input.required<string>()
@@ -157,23 +158,35 @@ describe('injectMutationState', () => {
         }))
       }
 
-      const fixture = TestBed.createComponent(FakeComponent)
-      const { debugElement } = fixture
-      setFixtureSignalInputs(fixture, { name: fakeName })
+      registerSignalInput(FakeComponent, 'name')
+
+      @Component({
+        template: `<app-fake [name]="name()" />`,
+        imports: [FakeComponent],
+      })
+      class HostComponent {
+        protected readonly name = signal(fakeName)
+      }
+
+      const fixture = TestBed.createComponent(HostComponent)
+      fixture.detectChanges()
       await vi.advanceTimersByTimeAsync(0)
 
-      let spans = debugElement
-        .queryAll(By.css('span'))
-        .map((span) => span.nativeNode.textContent)
+      const readSpans = () =>
+        Array.from(
+          fixture.nativeElement.querySelectorAll(
+            'span',
+          ) as NodeListOf<HTMLSpanElement>,
+        ).map((span) => span.textContent)
+
+      let spans = readSpans()
 
       expect(spans).toEqual(['pending', 'pending'])
 
       await vi.advanceTimersByTimeAsync(11)
       fixture.detectChanges()
 
-      spans = debugElement
-        .queryAll(By.css('span'))
-        .map((span) => span.nativeNode.textContent)
+      spans = readSpans()
 
       expect(spans).toEqual(['success', 'error'])
     })
diff --git a/packages/angular-query-experimental/src/__tests__/inject-mutation.test.ts b/packages/angular-query-experimental/src/__tests__/inject-mutation.test.ts
index 2adf0ee808..3daa657356 100644
--- a/packages/angular-query-experimental/src/__tests__/inject-mutation.test.ts
+++ b/packages/angular-query-experimental/src/__tests__/inject-mutation.test.ts
@@ -1,17 +1,19 @@
 import {
   ApplicationRef,
+  ChangeDetectionStrategy,
   Component,
   Injector,
+  NgZone,
   input,
   provideZonelessChangeDetection,
   signal,
 } from '@angular/core'
 import { TestBed } from '@angular/core/testing'
-import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'
-import { By } from '@angular/platform-browser'
 import { sleep } from '@tanstack/query-test-utils'
+import { firstValueFrom } from 'rxjs'
+import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'
 import { QueryClient, injectMutation, provideTanStackQuery } from '..'
-import { expectSignals, setFixtureSignalInputs } from './test-utils'
+import { expectSignals, registerSignalInput } from './test-utils'
 
 describe('injectMutation', () => {
   let queryClient: QueryClient
@@ -307,6 +309,7 @@ describe('injectMutation', () => {
         <button (click)="mutate()"></button>
         <span>{{ mutation.data() }}</span>
       `,
+      changeDetection: ChangeDetectionStrategy.OnPush,
     })
     class FakeComponent {
       name = input.required<string>()
@@ -321,19 +324,32 @@ describe('injectMutation', () => {
       }
     }
 
-    const fixture = TestBed.createComponent(FakeComponent)
-    const { debugElement } = fixture
-    setFixtureSignalInputs(fixture, { name: 'value' })
+    registerSignalInput(FakeComponent, 'name')
 
-    const button = debugElement.query(By.css('button'))
-    button.triggerEventHandler('click')
+    @Component({
+      template: `<app-fake [name]="name()" />`,
+      imports: [FakeComponent],
+    })
+    class HostComponent {
+      protected readonly name = signal('value')
+    }
+
+    const fixture = TestBed.createComponent(HostComponent)
+    fixture.detectChanges()
+
+    const hostButton = fixture.nativeElement.querySelector(
+      'button',
+    ) as HTMLButtonElement
+    hostButton.click()
 
     await vi.advanceTimersByTimeAsync(11)
     fixture.detectChanges()
 
-    const text = debugElement.query(By.css('span')).nativeElement.textContent
-    expect(text).toEqual('value')
-    const mutation = mutationCache.find({ mutationKey: ['fake', 'value'] })
+    const span = fixture.nativeElement.querySelector('span') as HTMLSpanElement
+    expect(span.textContent).toEqual('value')
+    const mutation = mutationCache.find({
+      mutationKey: ['fake', 'value'],
+    })
     expect(mutation).toBeDefined()
     expect(mutation!.options.mutationKey).toStrictEqual(['fake', 'value'])
   })
@@ -347,6 +363,7 @@ describe('injectMutation', () => {
         <button (click)="mutate()"></button>
         <span>{{ mutation.data() }}</span>
       `,
+      changeDetection: ChangeDetectionStrategy.OnPush,
     })
     class FakeComponent {
       name = input.required<string>()
@@ -361,26 +378,43 @@ describe('injectMutation', () => {
       }
     }
 
-    const fixture = TestBed.createComponent(FakeComponent)
-    const { debugElement } = fixture
-    setFixtureSignalInputs(fixture, { name: 'value' })
+    registerSignalInput(FakeComponent, 'name')
 
-    const button = debugElement.query(By.css('button'))
-    const span = debugElement.query(By.css('span'))
+    @Component({
+      template: `<app-fake [name]="name()" />`,
+      imports: [FakeComponent],
+    })
+    class HostComponent {
+      protected readonly name = signal('value')
 
-    button.triggerEventHandler('click')
+      updateName(value: string): void {
+        this.name.set(value)
+      }
+    }
+
+    const fixture = TestBed.createComponent(HostComponent)
+    fixture.detectChanges()
+
+    let button = fixture.nativeElement.querySelector(
+      'button',
+    ) as HTMLButtonElement
+    button.click()
     await vi.advanceTimersByTimeAsync(11)
     fixture.detectChanges()
 
-    expect(span.nativeElement.textContent).toEqual('value')
+    let span = fixture.nativeElement.querySelector('span') as HTMLSpanElement
+    expect(span.textContent).toEqual('value')
 
-    setFixtureSignalInputs(fixture, { name: 'updatedValue' })
+    fixture.componentInstance.updateName('updatedValue')
+    fixture.detectChanges()
 
-    button.triggerEventHandler('click')
+    button = fixture.nativeElement.querySelector('button') as HTMLButtonElement
+    button.click()
     await vi.advanceTimersByTimeAsync(11)
     fixture.detectChanges()
 
-    expect(span.nativeElement.textContent).toEqual('updatedValue')
+    span = fixture.nativeElement.querySelector('span') as HTMLSpanElement
+    expect(span.textContent).toEqual('updatedValue')
 
     const mutations = mutationCache.findAll()
     expect(mutations.length).toBe(2)
@@ -412,6 +446,36 @@ describe('injectMutation', () => {
       expect(boundaryFn).toHaveBeenCalledTimes(1)
       expect(boundaryFn).toHaveBeenCalledWith(err)
     })
+
+    test('should emit zone error when throwOnError is true and mutate is used', async () => {
+      const err = new Error('Expected mock error. All is well!')
+      const zone = TestBed.inject(NgZone)
+      const zoneErrorEmitSpy = vi.spyOn(zone.onError, 'emit')
+      const runSpy = vi.spyOn(zone, 'run').mockImplementation((callback: any) => {
+        try {
+          return callback()
+        } catch {
+          return undefined
+        }
+      })
+
+      const { mutate } = TestBed.runInInjectionContext(() =>
+        injectMutation(() => ({
+          mutationKey: ['fake'],
+          mutationFn: () => {
+            return sleep(0).then(() => Promise.reject(err))
+          },
+          throwOnError: true,
+        })),
+      )
+
+      mutate()
+
+      await vi.runAllTimersAsync()
+
+      expect(zoneErrorEmitSpy).toHaveBeenCalledWith(err)
+      expect(runSpy).toHaveBeenCalled()
+    })
   })
 
   test('should throw when throwOnError is true', async () => {
@@ -625,12 +689,13 @@ describe('injectMutation', () => {
 
       const mutation = TestBed.runInInjectionContext(() =>
         injectMutation(() => ({
-          mutationFn: async (data: string) => `final: ${data}`, // Synchronous resolution
+          mutationFn: async (data: string) => {
+            await sleep(50)
+            return `final: ${data}`
+          },
           onMutate: async (variables) => {
             onMutateCalled = true
-            const previousData = queryClient.getQueryData(testQueryKey)
             queryClient.setQueryData(testQueryKey, `optimistic: ${variables}`)
-            return { previousData }
           },
           onSuccess: (data) => {
             onSuccessCalled = true
@@ -639,19 +704,30 @@ describe('injectMutation', () => {
         })),
       )
 
+      // Run effects
+      TestBed.tick()
+
       // Start mutation
+      expect(queryClient.getQueryData(testQueryKey)).toBe('initial')
       mutation.mutate('test')
 
-      // Synchronize pending effects
-      TestBed.tick()
-
-      const stablePromise = app.whenStable()
       // Flush microtasks to allow TanStack Query's scheduled notifications to process
       await Promise.resolve()
-      await vi.advanceTimersByTimeAsync(1)
-      await stablePromise
 
+      // Check for optimistic update in the same macro task
       expect(onMutateCalled).toBe(true)
+      expect(queryClient.getQueryData(testQueryKey)).toBe('optimistic: test')
+
+      // Check stability before the mutation completes, waiting for the next macro task
+      await vi.advanceTimersByTimeAsync(0)
+      expect(mutation.isPending()).toBe(true)
+      expect(await firstValueFrom(app.isStable)).toBe(false)
+
+      // Wait for the mutation to complete
+      const stablePromise = app.whenStable()
+      await vi.advanceTimersByTimeAsync(60)
+      await stablePromise
+
       expect(onSuccessCalled).toBe(true)
       expect(mutation.isSuccess()).toBe(true)
       expect(mutation.data()).toBe('final: test')
diff --git a/packages/angular-query-experimental/src/__tests__/inject-queries.test-d.ts b/packages/angular-query-experimental/src/__tests__/inject-queries.test-d.ts
index 62547fd9e0..6c2e373e44 100644
--- a/packages/angular-query-experimental/src/__tests__/inject-queries.test-d.ts
+++ b/packages/angular-query-experimental/src/__tests__/inject-queries.test-d.ts
@@ -1,6 +1,5 @@
 import { describe, expectTypeOf, it } from 'vitest'
-import { skipToken } from '..'
-import { injectQueries } from '../inject-queries'
+import { injectQueries, skipToken } from '..'
 import { queryOptions } from '../query-options'
 import type { CreateQueryOptions, CreateQueryResult, OmitKeyof } from '..'
 import type { Signal } from '@angular/core'
@@ -175,3 +174,88 @@ describe('InjectQueries config object overload', () => {
     >()
   })
 })
+
+describe('InjectQueries combine', () => {
+  it('should provide the correct type for the combine function', () => {
+    injectQueries(() => ({
+      queries: [
+        {
+          queryKey: ['key'],
+          queryFn: () => Promise.resolve(1),
+        },
+        {
+          queryKey: ['key2'],
+          queryFn: () => Promise.resolve(true),
+        },
+      ],
+      combine: (results) => {
+        expectTypeOf(results[0].data).toEqualTypeOf<number | undefined>()
+        expectTypeOf(results[0].refetch).toBeCallableWith()
+        expectTypeOf(results[1].data).toEqualTypeOf<boolean | undefined>()
+        expectTypeOf(results[1].refetch).toBeCallableWith()
+      },
+    }))
+  })
+
+  it('should provide the correct types on the combined result with initial data', () => {
+    injectQueries(() => ({
+      queries: [
+        {
+          queryKey: ['key'],
+          queryFn: () => Promise.resolve(1),
+          initialData: 1,
+        },
+      ],
+      combine: (results) => {
+        expectTypeOf(results[0].data).toEqualTypeOf<number>()
+        expectTypeOf(results[0].refetch).toBeCallableWith()
+      },
+    }))
+  })
+
+  it('should provide the correct result type', () => {
+    const queryResults = injectQueries(() => ({
+      queries: [
+        {
+          queryKey: ['key'],
+          queryFn: () => Promise.resolve(1),
+        },
+        {
+          queryKey: ['key2'],
+          queryFn: () => Promise.resolve(true),
+        },
+      ],
+      combine: (results) => ({
+        data: {
+          1: results[0].data,
+          2: results[1].data,
+        },
+        fn: () => {},
+      }),
+    }))
+
+    expectTypeOf(queryResults).branded.toEqualTypeOf<
+      Signal<{
+        data: {
+          1: number | undefined
+          2: boolean | undefined
+        }
+        fn: () => void
+      }>
+    >()
+  })
+
+  it('should provide the correct types on the result with initial data', () => {
+    const queryResults = injectQueries(() => ({
+      queries: [
+        {
+          queryKey: ['key'],
+          queryFn: () => Promise.resolve(1),
+          initialData: 1,
+        },
+      ],
+    }))
+
+    expectTypeOf(queryResults()[0].data()).toEqualTypeOf<number>()
+  })
+})
diff --git a/packages/angular-query-experimental/src/__tests__/inject-queries.test.ts b/packages/angular-query-experimental/src/__tests__/inject-queries.test.ts
index 3fb3d5a626..3007a8db86 100644
--- a/packages/angular-query-experimental/src/__tests__/inject-queries.test.ts
+++ b/packages/angular-query-experimental/src/__tests__/inject-queries.test.ts
@@ -1,28 +1,64 @@
-import { beforeEach, describe, expect, it } from 'vitest'
+import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
 import { render } from '@testing-library/angular'
 import {
+  ApplicationRef,
+  ChangeDetectionStrategy,
   Component,
+  Injector,
+  computed,
   effect,
-  provideZonelessChangeDetection,
+  input,
+  signal,
 } from '@angular/core'
 import { TestBed } from '@angular/core/testing'
-import { queryKey } from '@tanstack/query-test-utils'
-import { QueryClient, provideTanStackQuery } from '..'
+import { queryKey, sleep } from '@tanstack/query-test-utils'
+import { QueryClient, provideIsRestoring } from '..'
 import { injectQueries } from '../inject-queries'
+import { registerSignalInput, setupTanStackQueryTestBed } from './test-utils'
 
 let queryClient: QueryClient
 
 beforeEach(() => {
   queryClient = new QueryClient()
-  TestBed.configureTestingModule({
-    providers: [
-      provideZonelessChangeDetection(),
-      provideTanStackQuery(queryClient),
-    ],
-  })
+  vi.useFakeTimers({ shouldAdvanceTime: true })
+  setupTanStackQueryTestBed(queryClient)
+})
+
+afterEach(() => {
+  vi.useRealTimers()
 })
 
 describe('injectQueries', () => {
+  it('throws NG0203 with descriptive error outside injection context', () => {
+    expect(() => {
+      injectQueries(() => ({
+        queries: [
+          {
+            queryKey: ['injectionContextError'],
+            queryFn: () => Promise.resolve(1),
+          },
+        ],
+      }))
+    }).toThrowError(/NG0203(.*?)injectQueries/)
+  })
+
+  it('can be used outside injection context when passing an injector', () => {
+    const injector = TestBed.inject(Injector)
+    const queries = injectQueries(
+      () => ({
+        queries: [
+          {
+            queryKey: ['manualInjector'],
+            queryFn: () => Promise.resolve(1),
+          },
+        ],
+      }),
+      injector,
+    )
+
+    expect(queries()[0].status()).toBe('pending')
+  })
+
   it('should return the correct states', async () => {
     const key1 = queryKey()
     const key2 = queryKey()
@@ -32,17 +68,18 @@ describe('injectQueries', () => {
       template: `
         <div>
           <div>
-            data1: {{ result()[0].data() ?? 'null' }}, data2:
-            {{ result()[1].data() ?? 'null' }}
+            data1: {{ queries()[0].data() ?? 'null' }}, data2:
+            {{ queries()[1].data() ?? 'null' }}
           </div>
         </div>
       `,
+      changeDetection: ChangeDetectionStrategy.OnPush,
     })
     class Page {
       toString(val: any) {
         return String(val)
       }
-      result = injectQueries(() => ({
+      queries = injectQueries(() => ({
         queries: [
           {
             queryKey: key1,
@@ -62,7 +99,7 @@ describe('injectQueries', () => {
       }))
 
       _pushResults = effect(() => {
-        const snapshot = this.result().map((q) => ({ data: q.data() }))
+        const snapshot = this.queries().map((q) => ({ data: q.data() }))
         results.push(snapshot)
       })
     }
@@ -76,4 +113,548 @@ describe('injectQueries', () => {
     expect(results[1]).toMatchObject([{ data: 1 }, { data: undefined }])
     expect(results[2]).toMatchObject([{ data: 1 }, { data: 2 }])
   })
+
+  it('should support combining results', async () => {
+    const key1 = queryKey()
+    const key2 = queryKey()
+    let count = 0
+
+    const results: Array<{ data: string; refetch: () => void }> = []
+
+    @Component({
+      template: ` <div>data: {{ queries().data }}</div> `,
+      changeDetection: ChangeDetectionStrategy.OnPush,
+    })
+    class Page {
+      queries = injectQueries(() => ({
+        queries: [
+          {
+            queryKey: key1,
+            queryFn: async () => {
+              await new Promise((r) => setTimeout(r, 10))
+              count++
+              return count
+            },
+          },
+          {
+            queryKey: key2,
+            queryFn: async () => {
+              await new Promise((r) => setTimeout(r, 100))
+              count++
+              return count
+            },
+          },
+        ],
+        combine: (queryResults) => {
+          return {
+            refetch: () => queryResults.forEach((r) => r.refetch()),
+            data: queryResults.map((r) => r.data).join(','),
+          }
+        },
+      }))
+
+      _pushResults = effect(() => {
+        results.push(this.queries())
+      })
+    }
+
+    const rendered = await render(Page)
+    const instance = rendered.fixture.componentInstance
+    await rendered.findByText('data: 1,2')
+    expect(instance.queries().data).toBe('1,2')
+
+    instance.queries().refetch()
+
+    await rendered.findByText('data: 3,4')
+    expect(instance.queries().data).toBe('3,4')
+
+    expect(results).toHaveLength(5)
+    expect(results[0]).toMatchObject({
+      data: ',',
+      refetch: expect.any(Function),
+    })
+    expect(results[1]).toMatchObject({
+      data: '1,',
+      refetch: expect.any(Function),
+    })
+    expect(results[2]).toMatchObject({
+      data: '1,2',
+      refetch: expect.any(Function),
+    })
+    expect(results[3]).toMatchObject({
+      data: '3,2',
+      refetch: expect.any(Function),
+    })
+    expect(results[4]).toMatchObject({
+      data: '3,4',
+      refetch: expect.any(Function),
+    })
+  })
+
+  it('should handle mixed success and error query states', async () => {
+    @Component({
+      template: '',
+      changeDetection: ChangeDetectionStrategy.OnPush,
+    })
+    class Page {
+      queries = injectQueries(() => ({
+        queries: [
+          {
+            queryKey: ['mixed-error'],
+            retry: false,
+            queryFn: async () => {
+              await new Promise((resolve) => setTimeout(resolve, 10))
+              throw new Error('mixed-error')
+            },
+          },
+          {
+            queryKey: ['mixed-success'],
+            queryFn: async () => {
+              await new Promise((resolve) => setTimeout(resolve, 20))
+              return 'mixed-success'
+            },
+          },
+        ],
+      }))
+    }
+
+    const rendered = await render(Page)
+    await vi.advanceTimersByTimeAsync(25)
+    await Promise.resolve()
+
+    const [errorQuery, successQuery] = rendered.fixture.componentInstance.queries()
+    expect(errorQuery.status()).toBe('error')
+    expect(errorQuery.error()?.message).toBe('mixed-error')
+    expect(successQuery.status()).toBe('success')
+    expect(successQuery.data()).toBe('mixed-success')
+  })
+
+  it('should cleanup pending tasks when component with active queries is destroyed', async () => {
+    @Component({
+      template: '',
+      changeDetection: ChangeDetectionStrategy.OnPush,
+    })
+    class Page {
+      queries = injectQueries(() => ({
+        queries: [
+          {
+            queryKey: ['destroy-query-1'],
+            queryFn: async () => {
+              await sleep(100)
+              return 'one'
+            },
+          },
+          {
+            queryKey: ['destroy-query-2'],
+            queryFn: async () => {
+              await sleep(100)
+              return 'two'
+            },
+          },
+        ],
+      }))
+    }
+
+    // Use a fixture here on purpose: we need component teardown + whenStable() semantics.
+    const fixture = TestBed.createComponent(Page)
+    fixture.detectChanges()
+    expect(fixture.isStable()).toBe(false)
+
+    fixture.destroy()
+
+    const stablePromise = fixture.whenStable()
+    await vi.advanceTimersByTimeAsync(150)
+    await stablePromise
+
+    expect(fixture.isStable()).toBe(true)
+  })
+
+  it('should react to enabled signal changes', async () => {
+    const enabled = signal(false)
+    const fetchSpy = vi.fn(() => sleep(10).then(() => 'enabled-data'))
+
+    @Component({
+      template: '',
+      changeDetection: ChangeDetectionStrategy.OnPush,
+    })
+    class Page {
+      enabled = enabled
+      fetchSpy = fetchSpy
+
+      queries = injectQueries(() => ({
+        queries: [
+          {
+            queryKey: ['enabled', this.enabled()],
+            queryFn: this.fetchSpy,
+            enabled: this.enabled(),
+          },
+        ],
+      }))
+    }
+
+    const rendered = await render(Page)
+    const query = rendered.fixture.componentInstance.queries()[0]
+
+    expect(fetchSpy).not.toHaveBeenCalled()
+    expect(query.status()).toBe('pending')
+
+    enabled.set(true)
+    rendered.fixture.detectChanges()
+    await vi.advanceTimersByTimeAsync(11)
+    await Promise.resolve()
+
+    expect(fetchSpy).toHaveBeenCalledTimes(1)
+    expect(query.status()).toBe('success')
+    expect(query.data()).toBe('enabled-data')
+  })
+
+  it('should refetch only changed keys when queries length stays the same', async () => {
+    const ids = signal<[string, string]>(['a', 'b'])
+    const firstSpy = vi.fn((context: any) =>
+      sleep(10).then(() => `first-${context.queryKey[1]}`),
+    )
+    const secondSpy = vi.fn((context: any) =>
+      sleep(10).then(() => `second-${context.queryKey[1]}`),
+    )
+
+    @Component({
+      template: '',
+      changeDetection: ChangeDetectionStrategy.OnPush,
+    })
+    class Page {
+      ids = ids
+      firstSpy = firstSpy
+      secondSpy = secondSpy
+
+      queries = injectQueries(() => ({
+        queries: [
+          {
+            staleTime: Number.POSITIVE_INFINITY,
+            queryKey: ['first', this.ids()[0]],
+            queryFn: this.firstSpy,
+          },
+          {
+            staleTime: Number.POSITIVE_INFINITY,
+            queryKey: ['second', this.ids()[1]],
+            queryFn: this.secondSpy,
+          },
+        ],
+      }))
+    }
+
+    const rendered = await render(Page)
+    await vi.advanceTimersByTimeAsync(11)
+    await Promise.resolve()
+
+    let [firstQuery, secondQuery] = rendered.fixture.componentInstance.queries()
+    expect(firstQuery.data()).toBe('first-a')
+    expect(secondQuery.data()).toBe('second-b')
+    expect(firstSpy).toHaveBeenCalledTimes(1)
+    expect(secondSpy).toHaveBeenCalledTimes(1)
+
+    ids.set(['c', 'b'])
+    rendered.fixture.detectChanges()
+    await vi.advanceTimersByTimeAsync(11)
+    await Promise.resolve()
+
+    ;[firstQuery, secondQuery] = rendered.fixture.componentInstance.queries()
+    expect(firstQuery.data()).toBe('first-c')
+    expect(secondQuery.data()).toBe('second-b')
+    expect(firstSpy).toHaveBeenCalledTimes(2)
+    expect(secondSpy).toHaveBeenCalledTimes(1)
+  })
+
+  it('should support changes on the queries array', async () => {
+    const results: Array<Array<Record<string, any>>> = []
+
+    @Component({
+      template: ` <div>data: {{ mapped() }}</div> `,
+      changeDetection: ChangeDetectionStrategy.OnPush,
+    })
+    class Page {
+      queries = injectQueries(() => ({
+        queries: queries().map((q) => ({
+          queryKey: ['query', q],
+          queryFn: async () => {
+            await new Promise((resolve) => setTimeout(resolve, 20 * q))
+            return q
+          },
+        })),
+      }))
+
+      mapped = computed(() => {
+        const queryData = this.queries().map((q) => q.data())
+        if (queryData.length === 0) return 'empty'
+        return queryData.join(',')
+      })
+
+      _pushResults = effect(() => {
+        const snapshot = this.queries().map((q) => ({ data: q.data() }))
+        results.push(snapshot)
+      })
+    }
+
+    const queries = signal([1, 2, 4])
+
+    const rendered = await render(Page)
+    const instance = rendered.fixture.componentInstance
+
+    await rendered.findByText('data: 1,2,4')
+    expect(instance.mapped()).toBe('1,2,4')
+
+    expect(results.length).toBe(4)
+    expect(results[0]).toMatchObject([
+      { data: undefined },
+      { data: undefined },
+      { data: undefined },
+    ])
+    expect(results[1]).toMatchObject([
+      { data: 1 },
+      { data: undefined },
+      { data: undefined },
+    ])
+    expect(results[2]).toMatchObject([
+      { data: 1 },
+      { data: 2 },
+      { data: undefined },
+    ])
+    expect(results[3]).toMatchObject([{ data: 1 }, { data: 2 }, { data: 4 }])
+
+    queries.set([3, 4])
+    await rendered.findByText('data: 3,4')
+    expect(instance.mapped()).toBe('3,4')
+
+    const hasOptimisticTransition = results.some(
+      (snapshot) =>
+        snapshot.length === 2 &&
+        snapshot[0]?.data === undefined &&
+        snapshot[1]?.data === 4,
+    )
+    expect(hasOptimisticTransition).toBe(true)
+    expect(results[results.length - 1]).toMatchObject([{ data: 3 }, { data: 4 }])
+
+    queries.set([])
+    await rendered.findByText('data: empty')
+    expect(instance.mapped()).toBe('empty')
+
+    expect(results[results.length - 1]).toMatchObject([])
+  })
+
+  it('should change the rendered component when the queries array changes', async () => {
+    const userIds = signal([1, 2])
+
+    @Component({
+      template: `
+        <ul>
+          @for (query of queries(); track $index) {
+            @if (query.data(); as data) {
+              <li>{{ data.value }}</li>
+            }
+          }
+        </ul>
+      `,
+      changeDetection: ChangeDetectionStrategy.OnPush,
+    })
+    class Page {
+      userIds = userIds
+
+      queries = injectQueries(() => ({
+        queries: this.userIds().map((id) => ({
+          queryKey: ['user', id],
+          queryFn: async () => {
+            await new Promise((resolve) => setTimeout(resolve, 20))
+            return { value: String(id) }
+          },
+        })),
+      }))
+    }
+
+    const rendered = await render(Page)
+
+    await rendered.findByText('1')
+    await rendered.findByText('2')
+
+    userIds.set([3])
+    rendered.fixture.detectChanges()
+
+    await rendered.findByText('3')
+    expect(rendered.queryByText('1')).toBeNull()
+    expect(rendered.queryByText('2')).toBeNull()
+  })
+
+  it('should support required signal inputs', async () => {
+    @Component({
+      selector: 'app-fake',
+      template: `{{ queries()[0].data() }}`,
+      changeDetection: ChangeDetectionStrategy.OnPush,
+    })
+    class FakeComponent {
+      name = input.required<string>()
+
+      queries = injectQueries(() => ({
+        queries: [
+          {
+            queryKey: ['fake', this.name()],
+            queryFn: () => this.name(),
+          },
+        ],
+      }))
+    }
+
+    registerSignalInput(FakeComponent, 'name')
+
+    @Component({
+      template: `<app-fake [name]="name()" />`,
+      imports: [FakeComponent],
+    })
+    class HostComponent {
+      protected readonly name = signal('signal-input-required-test')
+    }
+
+    const fixture = TestBed.createComponent(HostComponent)
+    fixture.detectChanges()
+    await vi.advanceTimersByTimeAsync(0)
+
+    const result = fixture.nativeElement.querySelector('app-fake').textContent
+    expect(result).toEqual('signal-input-required-test')
+  })
+
+  it('should pause fetching while restoring and fetch once restoring is disabled', async () => {
+    const isRestoring = signal(true)
+    const fetchSpy = vi.fn(() => sleep(10).then(() => 'restored-data'))
+    setupTanStackQueryTestBed(queryClient, {
+      providers: [provideIsRestoring(isRestoring.asReadonly())],
+    })
+
+    @Component({
+      template: '',
+      changeDetection: ChangeDetectionStrategy.OnPush,
+    })
+    class Page {
+      queries = injectQueries(() => ({
+        queries: [
+          {
+            queryKey: ['restoring'],
+            queryFn: fetchSpy,
+          },
+        ],
+      }))
+    }
+
+    const fixture = TestBed.createComponent(Page)
+    fixture.detectChanges()
+
+    expect(fetchSpy).not.toHaveBeenCalled()
+    expect(fixture.componentInstance.queries()[0].status()).toBe('pending')
+
+    const stablePromise = fixture.whenStable()
+    await Promise.resolve()
+    await stablePromise
+
+    isRestoring.set(false)
+    fixture.detectChanges()
+
+    await vi.advanceTimersByTimeAsync(11)
+    await fixture.whenStable()
+
+    const result = fixture.componentInstance.queries()[0]
+    expect(fetchSpy).toHaveBeenCalledTimes(1)
+    expect(result.status()).toBe('success')
+    expect(result.data()).toBe('restored-data')
+  })
+
+  it('should complete queries before whenStable resolves', async () => {
+    const app = TestBed.inject(ApplicationRef)
+
+    @Component({
+      template: '',
+      changeDetection: ChangeDetectionStrategy.OnPush,
+    })
+    class Page {
+      queries = injectQueries(() => ({
+        queries: [
+          {
+            queryKey: ['query-1'],
+            queryFn: async () => {
+              await new Promise((resolve) => setTimeout(resolve, 10))
+              return 1
+            },
+          },
+          {
+            queryKey: ['query-2'],
+            queryFn: async () => {
+              await new Promise((resolve) => setTimeout(resolve, 20))
+              return 2
+            },
+          },
+        ],
+      }))
+    }
+
+    const fixture = TestBed.createComponent(Page)
+    fixture.detectChanges()
+
+    const stablePromise = app.whenStable()
+    let stableResolved = false
+    void stablePromise.then(() => {
+      stableResolved = true
+    })
+
+    await Promise.resolve()
+    expect(stableResolved).toBe(false)
+
+    await vi.advanceTimersByTimeAsync(25)
+    await stablePromise
+
+    const result = fixture.componentInstance.queries()
+    expect(result[0].status()).toBe('success')
+    expect(result[1].status()).toBe('success')
+    expect(result[0].data()).toBe(1)
+    expect(result[1].data()).toBe(2)
+  })
+
+  it('should use latest query key for aliased refetch function', async () => {
+    const key = signal('one')
+    const fetchSpy = vi.fn(async (context: any) => {
+      await new Promise((resolve) => setTimeout(resolve, 10))
+      return context.queryKey[1]
+    })
+
+    @Component({
+      template: '',
+      changeDetection: ChangeDetectionStrategy.OnPush,
+    })
+    class Page {
+      key = key
+      fetchSpy = fetchSpy
+
+      queries = injectQueries(() => ({
+        queries: [
+          {
+            queryKey: ['query', this.key()],
+            queryFn: this.fetchSpy,
+            enabled: false,
+          },
+        ],
+      }))
+    }
+
+    const rendered = await render(Page)
+    const query = rendered.fixture.componentInstance.queries()[0]
+    const refetch = query.refetch
+
+    key.set('two')
+    rendered.fixture.detectChanges()
+
+    const refetchPromise = refetch()
+    await vi.advanceTimersByTimeAsync(15)
+    await refetchPromise
+
+    expect(fetchSpy).toHaveBeenCalledTimes(1)
+    expect(fetchSpy).toHaveBeenCalledWith(
+      expect.objectContaining({
+        queryKey: ['query', 'two'],
+      }),
+    )
+  })
 })
diff --git a/packages/angular-query-experimental/src/__tests__/inject-query.test-d.ts b/packages/angular-query-experimental/src/__tests__/inject-query.test-d.ts
index 541ad65f14..353890bff4 100644
--- a/packages/angular-query-experimental/src/__tests__/inject-query.test-d.ts
+++ b/packages/angular-query-experimental/src/__tests__/inject-query.test-d.ts
@@ -33,6 +33,18 @@ describe('initialData', () => {
       expectTypeOf(data).toEqualTypeOf<Signal<{ wow: boolean }>>()
     })
 
+    it('should support selection function with select', () => {
+      const options = injectQuery(() => ({
+        queryKey: ['key'],
+        queryFn: () => '1',
+        select: (data) => {
+          expectTypeOf(data).toEqualTypeOf<string>()
+          return parseInt(data)
+        },
+      }))
+      expectTypeOf(options.data).toEqualTypeOf<Signal<number | undefined>>()
+    })
+
     it('should be possible to define a different TData than TQueryFnData using select with queryOptions spread into useQuery', () => {
       const options = queryOptions({
         queryKey: ['key'],
diff --git a/packages/angular-query-experimental/src/__tests__/inject-query.test.ts b/packages/angular-query-experimental/src/__tests__/inject-query.test.ts
index 39d38140e3..e90054121b 100644
--- a/packages/angular-query-experimental/src/__tests__/inject-query.test.ts
+++ b/packages/angular-query-experimental/src/__tests__/inject-query.test.ts
@@ -1,7 +1,9 @@
 import {
   ApplicationRef,
+  ChangeDetectionStrategy,
   Component,
   Injector,
+  NgZone,
   computed,
   effect,
   input,
@@ -25,8 +27,14 @@ import {
 } from 'vitest'
 import { queryKey, sleep } from '@tanstack/query-test-utils'
 import { lastValueFrom } from 'rxjs'
-import { QueryCache, QueryClient, injectQuery, provideTanStackQuery } from '..'
-import { setSignalInputs } from './test-utils'
+import {
+  QueryCache,
+  QueryClient,
+  injectQuery,
+  provideIsRestoring,
+  provideTanStackQuery,
+} from '..'
+import { registerSignalInput } from './test-utils'
 import type { CreateQueryOptions, OmitKeyof, QueryFunction } from '..'
 
 describe('injectQuery', () => {
@@ -50,102 +58,190 @@ describe('injectQuery', () => {
 
   test('should return the correct types', () => {
     const key = queryKey()
-    // unspecified query function should default to unknown
-    const noQueryFn = TestBed.runInInjectionContext(() =>
-      injectQuery(() => ({
+
+    @Component({
+      selector: 'app-test',
+      template: '',
+      changeDetection: ChangeDetectionStrategy.OnPush,
+    })
+    class TestComponent {
+      // unspecified query function should default to unknown
+      noQueryFn = injectQuery(() => ({
         queryKey: key,
-      })),
-    )
-    expectTypeOf(noQueryFn.data()).toEqualTypeOf<unknown>()
-    expectTypeOf(noQueryFn.error()).toEqualTypeOf<Error | null>()
+      }))
 
-    // it should infer the result type from the query function
-    const fromQueryFn = TestBed.runInInjectionContext(() =>
-      injectQuery(() => ({
+      // it should infer the result type from the query function
+      fromQueryFn = injectQuery(() => ({
         queryKey: key,
         queryFn: () => 'test',
-      })),
-    )
-    expectTypeOf(fromQueryFn.data()).toEqualTypeOf<string | undefined>()
-    expectTypeOf(fromQueryFn.error()).toEqualTypeOf<Error | null>()
+      }))
 
-    // it should be possible to specify the result type
-    const withResult = TestBed.runInInjectionContext(() =>
-      injectQuery<string>(() => ({
+      // it should be possible to specify the result type
+      withResult = injectQuery<string>(() => ({
         queryKey: key,
         queryFn: () => 'test',
-      })),
-    )
-    expectTypeOf(withResult.data()).toEqualTypeOf<string | undefined>()
-    expectTypeOf(withResult.error()).toEqualTypeOf<Error | null>()
+      }))
 
-    // it should be possible to specify the error type
-    type CustomErrorType = { message: string }
-    const withError = TestBed.runInInjectionContext(() =>
-      injectQuery<string, CustomErrorType>(() => ({
+      // it should be possible to specify the error type
+      withError = injectQuery<string, { message: string }>(() => ({
         queryKey: key,
         queryFn: () => 'test',
-      })),
-    )
-    expectTypeOf(withError.data()).toEqualTypeOf<string | undefined>()
-    expectTypeOf(withError.error()).toEqualTypeOf<CustomErrorType | null>()
+      }))
 
-    // it should infer the result type from the configuration
-    const withResultInfer = TestBed.runInInjectionContext(() =>
-      injectQuery(() => ({
+      // it should infer the result type from the configuration
+      withResultInfer = injectQuery(() => ({
         queryKey: key,
         queryFn: () => true,
-      })),
-    )
-    expectTypeOf(withResultInfer.data()).toEqualTypeOf<boolean | undefined>()
-    expectTypeOf(withResultInfer.error()).toEqualTypeOf<Error | null>()
+      }))
 
-    // it should be possible to specify a union type as result type
-    const unionTypeSync = TestBed.runInInjectionContext(() =>
-      injectQuery(() => ({
+      // it should be possible to specify a union type as result type
+      unionTypeSync = injectQuery(() => ({
         queryKey: key,
         queryFn: () => (Math.random() > 0.5 ? ('a' as const) : ('b' as const)),
-      })),
-    )
-    expectTypeOf(unionTypeSync.data()).toEqualTypeOf<'a' | 'b' | undefined>()
-    const unionTypeAsync = TestBed.runInInjectionContext(() =>
-      injectQuery<'a' | 'b'>(() => ({
+      }))
+
+      unionTypeAsync = injectQuery<'a' | 'b'>(() => ({
         queryKey: key,
         queryFn: () => Promise.resolve(Math.random() > 0.5 ? 'a' : 'b'),
-      })),
-    )
-    expectTypeOf(unionTypeAsync.data()).toEqualTypeOf<'a' | 'b' | undefined>()
+      }))
 
-    // it should error when the query function result does not match with the specified type
-    TestBed.runInInjectionContext(() =>
-      // @ts-expect-error
-      injectQuery<number>(() => ({ queryKey: key, queryFn: () => 'test' })),
-    )
+      // it should infer the result type from a generic query function
+      fromGenericQueryFn = (() => {
+        function queryFn<T = string>(): Promise<T> {
+          return Promise.resolve({} as T)
+        }
+        return injectQuery(() => ({
+          queryKey: key,
+          queryFn: () => queryFn(),
+        }))
+      })()
 
-    // it should infer the result type from a generic query function
-    /**
-     *
-     */
-    function queryFn<T = string>(): Promise<T> {
-      return Promise.resolve({} as T)
-    }
+      // todo use query options?
+      fromGenericOptionsQueryFn = (() => {
+        function queryFn<T = string>(): Promise<T> {
+          return Promise.resolve({} as T)
+        }
+        return injectQuery(() => ({
+          queryKey: key,
+          queryFn: () => queryFn(),
+        }))
+      })()
+
+      fromMyDataArrayKeyQueryFn = (() => {
+        type MyData = number
+        type MyQueryKey = readonly ['my-data', number]
+        const getMyDataArrayKey: QueryFunction<MyData, MyQueryKey> = ({
+          queryKey: [, n],
+        }) => {
+          return n + 42
+        }
+        return injectQuery(() => ({
+          queryKey: ['my-data', 100] as const,
+          queryFn: getMyDataArrayKey,
+        }))
+      })()
 
-    const fromGenericQueryFn = TestBed.runInInjectionContext(() =>
-      injectQuery(() => ({
+      // it should handle query-functions that return Promise<any>
+      fromPromiseAnyQueryFn = injectQuery(() => ({
         queryKey: key,
-        queryFn: () => queryFn(),
-      })),
-    )
+        queryFn: () => fetch('return Promise<any>').then((resp) => resp.json()),
+      }))
+
+      fromGetMyDataStringKeyQueryFn = (() => {
+        type MyData = number
+        const getMyDataStringKey: QueryFunction<MyData, ['1']> = (context) => {
+          expectTypeOf(context.queryKey).toEqualTypeOf<['1']>()
+          return Number(context.queryKey[0]) + 42
+        }
+        return injectQuery(() => ({
+          queryKey: ['1'] as ['1'],
+          queryFn: getMyDataStringKey,
+        }))
+      })()
+
+      // Wrapped queries
+      fromWrappedQuery = (() => {
+        const createWrappedQuery = <
+          TQueryKey extends [string, Record<string, unknown>?],
+          TQueryFnData,
+          TError,
+          TData = TQueryFnData,
+        >(
+          qk: TQueryKey,
+          fetcher: (obj: TQueryKey[1], token: string) => Promise<TQueryFnData>,
+          options?: OmitKeyof<
+            CreateQueryOptions<TQueryFnData, TError, TData, TQueryKey>,
+            'queryKey' | 'queryFn' | 'initialData',
+            'safely'
+          >,
+        ) =>
+          injectQuery(() => ({
+            queryKey: qk,
+            queryFn: () => fetcher(qk[1], 'token'),
+            ...options,
+          }))
+        return createWrappedQuery([''], () => Promise.resolve('1'))
+      })()
+
+      fromWrappedFuncStyleQuery = (() => {
+        const createWrappedFuncStyleQuery = <
+          TQueryKey extends [string, Record<string, unknown>?],
+          TQueryFnData,
+          TError,
+          TData = TQueryFnData,
+        >(
+          qk: TQueryKey,
+          fetcher: () => Promise<TQueryFnData>,
+          options?: OmitKeyof<
+            CreateQueryOptions<TQueryFnData, TError, TData, TQueryKey>,
+            'queryKey' | 'queryFn' | 'initialData',
+            'safely'
+          >,
+        ) => injectQuery(() => ({ queryKey: qk, queryFn: fetcher, ...options }))
+        return createWrappedFuncStyleQuery([''], () => Promise.resolve(true))
+      })()
+    }
+
+    const fixture = TestBed.createComponent(TestComponent)
+    fixture.detectChanges()
+    const {
+      noQueryFn,
+      fromQueryFn,
+      withResult,
+      withError,
+      withResultInfer,
+      unionTypeSync,
+      unionTypeAsync,
+      fromGenericQueryFn,
+      fromGenericOptionsQueryFn,
+      fromMyDataArrayKeyQueryFn,
+      fromPromiseAnyQueryFn,
+      fromGetMyDataStringKeyQueryFn,
+      fromWrappedQuery,
+      fromWrappedFuncStyleQuery,
+    } = fixture.componentInstance
+
+    expectTypeOf(noQueryFn.data()).toEqualTypeOf<unknown>()
+    expectTypeOf(noQueryFn.error()).toEqualTypeOf<Error | null>()
+
+    expectTypeOf(fromQueryFn.data()).toEqualTypeOf<string | undefined>()
+    expectTypeOf(fromQueryFn.error()).toEqualTypeOf<Error | null>()
+
+    expectTypeOf(withResult.data()).toEqualTypeOf<string | undefined>()
+    expectTypeOf(withResult.error()).toEqualTypeOf<Error | null>()
+
+    expectTypeOf(withError.data()).toEqualTypeOf<string | undefined>()
+    expectTypeOf(withError.error()).toEqualTypeOf<{ message: string } | null>()
+
+    expectTypeOf(withResultInfer.data()).toEqualTypeOf<boolean | undefined>()
+    expectTypeOf(withResultInfer.error()).toEqualTypeOf<Error | null>()
+
+    expectTypeOf(unionTypeSync.data()).toEqualTypeOf<'a' | 'b' | undefined>()
+    expectTypeOf(unionTypeAsync.data()).toEqualTypeOf<'a' | 'b' | undefined>()
+
     expectTypeOf(fromGenericQueryFn.data()).toEqualTypeOf<string | undefined>()
     expectTypeOf(fromGenericQueryFn.error()).toEqualTypeOf<Error | null>()
 
-    // todo use query options?
-    const fromGenericOptionsQueryFn = TestBed.runInInjectionContext(() =>
-      injectQuery(() => ({
-        queryKey: key,
-        queryFn: () => queryFn(),
-      })),
-    )
     expectTypeOf(fromGenericOptionsQueryFn.data()).toEqualTypeOf<
       string | undefined
     >()
@@ -153,120 +249,36 @@ describe('injectQuery', () => {
       fromGenericOptionsQueryFn.error(),
     ).toEqualTypeOf<Error | null>()
 
-    type MyData = number
-    type MyQueryKey = readonly ['my-data', number]
-
-    const getMyDataArrayKey: QueryFunction<MyData, MyQueryKey> = ({
-      queryKey: [, n],
-    }) => {
-      return n + 42
-    }
-
-    const fromMyDataArrayKeyQueryFn = TestBed.runInInjectionContext(() =>
-      injectQuery(() => ({
-        queryKey: ['my-data', 100] as const,
-        queryFn: getMyDataArrayKey,
-      })),
-    )
     expectTypeOf(fromMyDataArrayKeyQueryFn.data()).toEqualTypeOf<
       number | undefined
     >()
 
-    // it should handle query-functions that return Promise<any>
-    const fromPromiseAnyQueryFn = TestBed.runInInjectionContext(() =>
-      injectQuery(() => ({
-        queryKey: key,
-        queryFn: () => fetch('return Promise<any>').then((resp) => resp.json()),
-      })),
-    )
     expectTypeOf(fromPromiseAnyQueryFn.data()).toEqualTypeOf<any | undefined>()
-
-    TestBed.runInInjectionContext(() =>
-      effect(() => {
-        expect(fromMyDataArrayKeyQueryFn.data()).toBe(142)
-      }),
-    )
-
-    const getMyDataStringKey: QueryFunction<MyData, ['1']> = (context) => {
-      expectTypeOf(context.queryKey).toEqualTypeOf<['1']>()
-      return Number(context.queryKey[0]) + 42
-    }
-
-    const fromGetMyDataStringKeyQueryFn = TestBed.runInInjectionContext(() =>
-      injectQuery(() => ({
-        queryKey: ['1'] as ['1'],
-        queryFn: getMyDataStringKey,
-      })),
-    )
     expectTypeOf(fromGetMyDataStringKeyQueryFn.data()).toEqualTypeOf<
       number | undefined
     >()
-
-    TestBed.runInInjectionContext(() =>
-      effect(() => {
-        expect(fromGetMyDataStringKeyQueryFn.data()).toBe(43)
-      }),
-    )
-
-    // handles wrapped queries with custom fetcher passed as inline queryFn
-    const createWrappedQuery = <
-      TQueryKey extends [string, Record<string, unknown>?],
-      TQueryFnData,
-      TError,
-      TData = TQueryFnData,
-    >(
-      qk: TQueryKey,
-      fetcher: (
-        obj: TQueryKey[1],
-        token: string,
-        // return type must be wrapped with TQueryFnReturn
-      ) => Promise<TQueryFnData>,
-      options?: OmitKeyof<
-        CreateQueryOptions<TQueryFnData, TError, TData, TQueryKey>,
-        'queryKey' | 'queryFn' | 'initialData',
-        'safely'
-      >,
-    ) =>
-      injectQuery(() => ({
-        queryKey: qk,
-        queryFn: () => fetcher(qk[1], 'token'),
-        ...options,
-      }))
-    const fromWrappedQuery = TestBed.runInInjectionContext(() =>
-      createWrappedQuery([''], () => Promise.resolve('1')),
-    )
     expectTypeOf(fromWrappedQuery.data()).toEqualTypeOf<string | undefined>()
-
-    // handles wrapped queries with custom fetcher passed directly to createQuery
-    const createWrappedFuncStyleQuery = <
-      TQueryKey extends [string, Record<string, unknown>?],
-      TQueryFnData,
-      TError,
-      TData = TQueryFnData,
-    >(
-      qk: TQueryKey,
-      fetcher: () => Promise<TQueryFnData>,
-      options?: OmitKeyof<
-        CreateQueryOptions<TQueryFnData, TError, TData, TQueryKey>,
-        'queryKey' | 'queryFn' | 'initialData',
-        'safely'
-      >,
-    ) => injectQuery(() => ({ queryKey: qk, queryFn: fetcher, ...options }))
-    const fromWrappedFuncStyleQuery = TestBed.runInInjectionContext(() =>
-      createWrappedFuncStyleQuery([''], () => Promise.resolve(true)),
-    )
     expectTypeOf(fromWrappedFuncStyleQuery.data()).toEqualTypeOf<
       boolean | undefined
     >()
   })
 
   test('should return pending status initially', () => {
-    const query = TestBed.runInInjectionContext(() => {
-      return injectQuery(() => ({
+    @Component({
+      selector: 'app-test',
+      template: '',
+      changeDetection: ChangeDetectionStrategy.OnPush,
+    })
+    class TestComponent {
+      query = injectQuery(() => ({
         queryKey: ['key1'],
         queryFn: () => sleep(10).then(() => 'Some data'),
       }))
-    })
+    }
+
+    const fixture = TestBed.createComponent(TestComponent)
+    fixture.detectChanges()
+    const query = fixture.componentInstance.query
 
     expect(query.status()).toBe('pending')
     expect(query.isPending()).toBe(true)
@@ -276,12 +288,21 @@ describe('injectQuery', () => {
   })
 
   test('should resolve to success and update signal: injectQuery()', async () => {
-    const query = TestBed.runInInjectionContext(() => {
-      return injectQuery(() => ({
+    @Component({
+      selector: 'app-test',
+      template: '',
+      changeDetection: ChangeDetectionStrategy.OnPush,
+    })
+    class TestComponent {
+      query = injectQuery(() => ({
         queryKey: ['key2'],
         queryFn: () => sleep(10).then(() => 'result2'),
       }))
-    })
+    }
+
+    const fixture = TestBed.createComponent(TestComponent)
+    fixture.detectChanges()
+    const query = fixture.componentInstance.query
 
     await vi.advanceTimersByTimeAsync(11)
     expect(query.status()).toBe('success')
@@ -293,14 +314,23 @@ describe('injectQuery', () => {
   })
 
   test('should reject and update signal', async () => {
-    const query = TestBed.runInInjectionContext(() => {
-      return injectQuery(() => ({
+    @Component({
+      selector: 'app-test',
+      template: '',
+      changeDetection: ChangeDetectionStrategy.OnPush,
+    })
+    class TestComponent {
+      query = injectQuery(() => ({
         retry: false,
         queryKey: ['key3'],
         queryFn: () =>
           sleep(10).then(() => Promise.reject(new Error('Some error'))),
       }))
-    })
+    }
+
+    const fixture = TestBed.createComponent(TestComponent)
+    fixture.detectChanges()
+    const query = fixture.componentInstance.query
 
     await vi.advanceTimersByTimeAsync(11)
     expect(query.status()).toBe('error')
@@ -317,12 +347,23 @@ describe('injectQuery', () => {
     const key = signal(['key6', 'key7'])
     const spy = vi.fn(() => sleep(10).then(() => 'Some data'))
 
-    const query = TestBed.runInInjectionContext(() => {
-      return injectQuery(() => ({
-        queryKey: key(),
-        queryFn: spy,
-      }))
+    @Component({
+      selector: 'app-test',
+      template: '',
+      changeDetection: ChangeDetectionStrategy.OnPush,
     })
+    class TestComponent {
+      key = key
+      spy = spy
+      query = injectQuery(() => ({
+        queryKey: this.key(),
+        queryFn: this.spy,
+      }))
+    }
+
+    const fixture = TestBed.createComponent(TestComponent)
+    fixture.detectChanges()
+    const query = fixture.componentInstance.query
 
     await vi.advanceTimersByTimeAsync(0)
     expect(spy).toHaveBeenCalledTimes(1)
@@ -331,7 +372,7 @@ describe('injectQuery', () => {
     expect(query.status()).toBe('success')
 
     key.set(['key8'])
-    TestBed.tick()
+    fixture.detectChanges()
 
     expect(spy).toHaveBeenCalledTimes(2)
     // should call queryFn with context containing the new queryKey
@@ -347,13 +388,24 @@ describe('injectQuery', () => {
     const spy = vi.fn(() => sleep(10).then(() => 'Some data'))
     const enabled = signal(false)
 
-    const query = TestBed.runInInjectionContext(() => {
-      return injectQuery(() => ({
+    @Component({
+      selector: 'app-test',
+      template: '',
+      changeDetection: ChangeDetectionStrategy.OnPush,
+    })
+    class TestComponent {
+      enabled = enabled
+      spy = spy
+      query = injectQuery(() => ({
         queryKey: ['key9'],
-        queryFn: spy,
-        enabled: enabled(),
+        queryFn: this.spy,
+        enabled: this.enabled(),
       }))
-    })
+    }
+
+    const fixture = TestBed.createComponent(TestComponent)
+    fixture.detectChanges()
+    const query = fixture.componentInstance.query
 
     expect(spy).not.toHaveBeenCalled()
     expect(query.status()).toBe('pending')
@@ -366,26 +418,33 @@ describe('injectQuery', () => {
   })
 
   test('should properly execute dependant queries', async () => {
-    const query1 = TestBed.runInInjectionContext(() => {
-      return injectQuery(() => ({
-        queryKey: ['dependant1'],
-        queryFn: () => sleep(10).then(() => 'Some data'),
-      }))
-    })
-
     const dependentQueryFn = vi
       .fn()
       .mockImplementation(() => sleep(1000).then(() => 'Some data'))
 
-    const query2 = TestBed.runInInjectionContext(() => {
-      return injectQuery(
+    @Component({
+      selector: 'app-test',
+      template: '',
+      changeDetection: ChangeDetectionStrategy.OnPush,
+    })
+    class TestComponent {
+      query1 = injectQuery(() => ({
+        queryKey: ['dependant1'],
+        queryFn: () => sleep(10).then(() => 'Some data'),
+      }))
+
+      query2 = injectQuery(
         computed(() => ({
           queryKey: ['dependant2'],
           queryFn: dependentQueryFn,
-          enabled: !!query1.data(),
+          enabled: !!this.query1.data(),
         })),
       )
-    })
+    }
+
+    const fixture = TestBed.createComponent(TestComponent)
+    fixture.detectChanges()
+    const { query1, query2 } = fixture.componentInstance
 
     expect(query1.data()).toStrictEqual(undefined)
     expect(query2.fetchStatus()).toStrictEqual('idle')
@@ -410,13 +469,24 @@ describe('injectQuery', () => {
     const fetchFn = vi.fn(() => sleep(10).then(() => 'Some data'))
     const keySignal = signal('key11')
 
-    const query = TestBed.runInInjectionContext(() => {
-      return injectQuery(() => ({
-        queryKey: ['key10', keySignal()],
-        queryFn: fetchFn,
+    @Component({
+      selector: 'app-test',
+      template: '',
+      changeDetection: ChangeDetectionStrategy.OnPush,
+    })
+    class TestComponent {
+      keySignal = keySignal
+      fetchFn = fetchFn
+      query = injectQuery(() => ({
+        queryKey: ['key10', this.keySignal()],
+        queryFn: this.fetchFn,
         enabled: false,
       }))
-    })
+    }
+
+    const fixture = TestBed.createComponent(TestComponent)
+    fixture.detectChanges()
+    const query = fixture.componentInstance.query
 
     expect(fetchFn).not.toHaveBeenCalled()
 
@@ -432,6 +502,7 @@ describe('injectQuery', () => {
     await vi.advanceTimersByTimeAsync(11)
 
     keySignal.set('key12')
+    fixture.detectChanges()
 
     void query.refetch().then(() => {
       expect(fetchFn).toHaveBeenCalledTimes(2)
@@ -445,18 +516,58 @@ describe('injectQuery', () => {
     await vi.advanceTimersByTimeAsync(11)
   })
 
+  test('should support selection function with select', async () => {
+    const app = TestBed.inject(ApplicationRef)
+
+    @Component({
+      selector: 'app-test',
+      template: '',
+      changeDetection: ChangeDetectionStrategy.OnPush,
+    })
+    class TestComponent {
+      query = injectQuery(() => ({
+        queryKey: ['key13'],
+        queryFn: () => [{ id: 1 }, { id: 2 }],
+        select: (data) => data.map((item) => item.id),
+      }))
+    }
+
+    const fixture = TestBed.createComponent(TestComponent)
+    fixture.detectChanges()
+    const query = fixture.componentInstance.query
+
+    // Wait for query to complete (even synchronous queryFn needs time to process)
+    const stablePromise = app.whenStable()
+    await Promise.resolve()
+    await vi.advanceTimersByTimeAsync(10)
+    await stablePromise
+
+    expect(query.status()).toBe('success')
+    expect(query.data()).toEqual([1, 2])
+  })
+
   describe('throwOnError', () => {
     test('should evaluate throwOnError when query is expected to throw', async () => {
       const boundaryFn = vi.fn()
-      TestBed.runInInjectionContext(() => {
-        return injectQuery(() => ({
+
+      @Component({
+        selector: 'app-test',
+        template: '',
+        changeDetection: ChangeDetectionStrategy.OnPush,
+      })
+      class TestComponent {
+        boundaryFn = boundaryFn
+        query = injectQuery(() => ({
           queryKey: ['key12'],
           queryFn: () =>
             sleep(10).then(() => Promise.reject(new Error('Some error'))),
           retry: false,
-          throwOnError: boundaryFn,
+          throwOnError: this.boundaryFn,
         }))
-      })
+      }
+
+      const fixture = TestBed.createComponent(TestComponent)
+      fixture.detectChanges()
 
       await vi.advanceTimersByTimeAsync(11)
       expect(boundaryFn).toHaveBeenCalledTimes(1)
@@ -469,41 +580,112 @@ describe('injectQuery', () => {
     })
 
     test('should throw when throwOnError is true', async () => {
-      TestBed.runInInjectionContext(() => {
-        return injectQuery(() => ({
+      const zone = TestBed.inject(NgZone)
+      const zoneErrorPromise = new Promise<Error>((resolve) => {
+        const sub = zone.onError.subscribe((error) => {
+          sub.unsubscribe()
+          resolve(error as Error)
+        })
+      })
+      let handler: ((error: Error) => void) | null = null
+      const processErrorPromise = new Promise<Error>((resolve) => {
+        handler = (error: Error) => {
+          process.off('uncaughtException', handler!)
+          resolve(error)
+        }
+        process.on('uncaughtException', handler)
+      })
+
+      @Component({
+        selector: 'app-test',
+        template: '',
+        changeDetection: ChangeDetectionStrategy.OnPush,
+      })
+      class TestComponent {
+        query = injectQuery(() => ({
           queryKey: ['key13'],
           queryFn: () =>
             sleep(0).then(() => Promise.reject(new Error('Some error'))),
           throwOnError: true,
         }))
-      })
-
-      await expect(vi.runAllTimersAsync()).rejects.toThrow('Some error')
+      }
+
+      TestBed.createComponent(TestComponent).detectChanges()
+
+      try {
+        await vi.runAllTimersAsync()
+        await expect(zoneErrorPromise).resolves.toEqual(Error('Some error'))
+        await expect(processErrorPromise).resolves.toEqual(Error('Some error'))
+      } finally {
+        if (handler) {
+          process.off('uncaughtException', handler)
+        }
+      }
     })
 
     test('should throw when throwOnError function returns true', async () => {
-      TestBed.runInInjectionContext(() => {
-        return injectQuery(() => ({
+      const zone = TestBed.inject(NgZone)
+      const zoneErrorPromise = new Promise<Error>((resolve) => {
+        const sub = zone.onError.subscribe((error) => {
+          sub.unsubscribe()
+          resolve(error as Error)
+        })
+      })
+      let handler: ((error: Error) => void) | null = null
+      const processErrorPromise = new Promise<Error>((resolve) => {
+        handler = (error: Error) => {
+          process.off('uncaughtException', handler!)
+          resolve(error)
+        }
+        process.on('uncaughtException', handler)
+      })
+
+      @Component({
+        selector: 'app-test',
+        template: '',
+        changeDetection: ChangeDetectionStrategy.OnPush,
+      })
+      class TestComponent {
+        query = injectQuery(() => ({
           queryKey: ['key14'],
           queryFn: () =>
             sleep(0).then(() => Promise.reject(new Error('Some error'))),
           throwOnError: () => true,
         }))
-      })
-
-      await expect(vi.runAllTimersAsync()).rejects.toThrow('Some error')
+      }
+
+      TestBed.createComponent(TestComponent).detectChanges()
+
+      try {
+        await vi.runAllTimersAsync()
+        await expect(zoneErrorPromise).resolves.toEqual(Error('Some error'))
+        await expect(processErrorPromise).resolves.toEqual(Error('Some error'))
+      } finally {
+        if (handler) {
+          process.off('uncaughtException', handler)
+        }
+      }
     })
   })
 
   test('should set state to error when queryFn returns reject promise', async () => {
-    const query = TestBed.runInInjectionContext(() => {
-      return injectQuery(() => ({
+    @Component({
+      selector: 'app-test',
+      template: '',
+      changeDetection: ChangeDetectionStrategy.OnPush,
+    })
+    class TestComponent {
+      query = injectQuery(() => ({
         retry: false,
         queryKey: ['key15'],
         queryFn: () =>
           sleep(10).then(() => Promise.reject(new Error('Some error'))),
       }))
-    })
+    }
+
+    const fixture = TestBed.createComponent(TestComponent)
+    fixture.detectChanges()
+    const query = fixture.componentInstance.query
 
     expect(query.status()).toBe('pending')
 
@@ -516,6 +698,7 @@ describe('injectQuery', () => {
     @Component({
       selector: 'app-fake',
       template: `{{ query.data() }}`,
+      changeDetection: ChangeDetectionStrategy.OnPush,
     })
     class FakeComponent {
       name = input.required<string>()
@@ -526,17 +709,225 @@ describe('injectQuery', () => {
       }))
     }
 
-    const fixture = TestBed.createComponent(FakeComponent)
-    setSignalInputs(fixture.componentInstance, {
-      name: 'signal-input-required-test',
+    registerSignalInput(FakeComponent, 'name')
+
+    @Component({
+      template: `<app-fake [name]="name()" />`,
+      imports: [FakeComponent],
+    })
+    class HostComponent {
+      protected readonly name = signal('signal-input-required-test')
+    }
+
+    const fixture = TestBed.createComponent(HostComponent)
+    fixture.detectChanges()
+    await vi.advanceTimersByTimeAsync(0)
+
+    const result = fixture.nativeElement.querySelector('app-fake').textContent
+    expect(result).toEqual('signal-input-required-test')
+  })
+
+  test('should support aliasing query.data on required signal inputs', async () => {
+    @Component({
+      selector: 'app-fake',
+      template: `{{ data() }}`,
+      changeDetection: ChangeDetectionStrategy.OnPush,
+    })
+    class FakeComponent {
+      name = input.required<string>()
+
+      query = injectQuery(() => ({
+        queryKey: ['fake-alias', this.name()],
+        queryFn: () => this.name(),
+      }))
+
+      data = this.query.data
+    }
+
+    registerSignalInput(FakeComponent, 'name')
+
+    @Component({
+      template: `<app-fake [name]="name()" />`,
+      imports: [FakeComponent],
     })
+    class HostComponent {
+      protected readonly name = signal('signal-input-alias-test')
+    }
 
+    const fixture = TestBed.createComponent(HostComponent)
     fixture.detectChanges()
     await vi.advanceTimersByTimeAsync(0)
 
-    expect(fixture.componentInstance.query.data()).toEqual(
-      'signal-input-required-test',
+    const result = fixture.nativeElement.querySelector('app-fake').textContent
+    expect(result).toEqual('signal-input-alias-test')
+  })
+
+  test('should allow reading the query data on effect registered before injection', () => {
+    const spy = vi.fn()
+    @Component({
+      selector: 'app-test',
+      template: '',
+      changeDetection: ChangeDetectionStrategy.OnPush,
+    })
+    class TestComponent {
+      readEffect = effect(() => {
+        spy(this.query.data())
+      })
+
+      query = injectQuery(() => ({
+        queryKey: ['effect-before-injection'],
+        queryFn: () => sleep(0).then(() => 'Some data'),
+      }))
+    }
+
+    const fixture = TestBed.createComponent(TestComponent)
+    fixture.detectChanges()
+    expect(spy).toHaveBeenCalledWith(undefined)
+  })
+
+  test('should render with an initial value for input signal if available before change detection', () => {
+    const key1 = queryKey()
+    const key2 = queryKey()
+
+    queryClient.setQueryData(key1, 'value 1')
+    queryClient.setQueryData(key2, 'value 2')
+
+    @Component({
+      selector: 'app-test',
+      template: '{{ query.data() }}',
+      changeDetection: ChangeDetectionStrategy.OnPush,
+    })
+    class TestComponent {
+      inputKey = input.required<[string]>()
+      query = injectQuery(() => ({
+        queryKey: this.inputKey(),
+        queryFn: () => sleep(0).then(() => 'Some data'),
+      }))
+    }
+    registerSignalInput(TestComponent, 'inputKey')
+
+    const fixture = TestBed.createComponent(TestComponent)
+    fixture.componentRef.setInput('inputKey', key1)
+
+    const instance = fixture.componentInstance
+    const query = instance.query
+
+    expect(() => instance.inputKey()).not.toThrow()
+
+    expect(instance.inputKey()).toEqual(key1)
+    expect(query.data()).toEqual('value 1')
+
+    fixture.componentRef.setInput('inputKey', key2)
+
+    expect(instance.inputKey()).toEqual(key2)
+    expect(query.data()).toEqual('value 2')
+  })
+
+  test('should allow reading the query data on component ngOnInit with required signal input', async () => {
+    const spy = vi.fn()
+    @Component({
+      selector: 'app-test',
+      template: '',
+      changeDetection: ChangeDetectionStrategy.OnPush,
+    })
+    class TestComponent {
+      key = input.required<[string]>()
+      query = injectQuery(() => ({
+        queryKey: this.key(),
+        queryFn: () => Promise.resolve(() => 'Some data'),
+      }))
+
+      initialStatus!: string
+
+      ngOnInit() {
+        this.initialStatus = this.query.status()
+
+        // effect should not have been called yet
+        expect(spy).not.toHaveBeenCalled()
+      }
+
+      _spyEffect = effect(() => {
+        spy()
+      })
+    }
+
+    registerSignalInput(TestComponent, 'key')
+
+    const fixture = TestBed.createComponent(TestComponent)
+    fixture.componentRef.setInput('key', ['ngOnInitTest'])
+
+    fixture.detectChanges()
+    expect(spy).toHaveBeenCalled()
+
+    const instance = fixture.componentInstance
+    expect(instance.initialStatus).toEqual('pending')
+  })
+
+  test('should update query data on the same macro task when query data changes', async () => {
+    const query = TestBed.runInInjectionContext(() =>
+      injectQuery(() => ({
+        queryKey: ['test'],
+        initialData: 'initial data',
+      })),
     )
+
+    // Run effects
+    TestBed.tick()
+
+    expect(query.data()).toBe('initial data')
+    queryClient.setQueryData(['test'], 'new data')
+
+    // Flush microtasks
+    await Promise.resolve()
+
+    expect(query.data()).toBe('new data')
+  })
+
+  test('should pause fetching while restoring and fetch once restoring is disabled', async () => {
+    const isRestoring = signal(true)
+    const fetchSpy = vi.fn(() => sleep(10).then(() => 'restored-data'))
+
+    TestBed.resetTestingModule()
+    TestBed.configureTestingModule({
+      providers: [
+        provideZonelessChangeDetection(),
+        provideTanStackQuery(queryClient),
+        provideIsRestoring(isRestoring.asReadonly()),
+      ],
+    })
+
+    @Component({
+      selector: 'app-test',
+      template: '',
+      changeDetection: ChangeDetectionStrategy.OnPush,
+    })
+    class TestComponent {
+      query = injectQuery(() => ({
+        queryKey: ['restoring'],
+        queryFn: fetchSpy,
+      }))
+    }
+
+    const fixture = TestBed.createComponent(TestComponent)
+    fixture.detectChanges()
+
+    const query = fixture.componentInstance.query
+    expect(fetchSpy).not.toHaveBeenCalled()
+    expect(query.status()).toBe('pending')
+
+    const stablePromise = fixture.whenStable()
+    await Promise.resolve()
+    await stablePromise
+
+    isRestoring.set(false)
+    fixture.detectChanges()
+
+    await vi.advanceTimersByTimeAsync(11)
+    await fixture.whenStable()
+
+    expect(fetchSpy).toHaveBeenCalledTimes(1)
+    expect(query.status()).toBe('success')
+    expect(query.data()).toBe('restored-data')
   })
 
   describe('injection context', () => {
@@ -550,15 +941,28 @@ describe('injectQuery', () => {
     })
 
     test('can be used outside injection context when passing an injector', () => {
-      const query = injectQuery(
-        () => ({
-          queryKey: ['manualInjector'],
-          queryFn: () => sleep(0).then(() => 'Some data'),
-        }),
-        {
-          injector: TestBed.inject(Injector),
-        },
-      )
+      const injector = TestBed.inject(Injector)
+
+      @Component({
+        selector: 'app-test',
+        template: '',
+        changeDetection: ChangeDetectionStrategy.OnPush,
+      })
+      class TestComponent {
+        query = injectQuery(
+          () => ({
+            queryKey: ['manualInjector'],
+            queryFn: () => sleep(0).then(() => 'Some data'),
+          }),
+          {
+            injector: injector,
+          },
+        )
+      }
+
+      const fixture = TestBed.createComponent(TestComponent)
+      fixture.detectChanges()
+      const query = fixture.componentInstance.query
 
       expect(query.status()).toBe('pending')
     })
@@ -566,22 +970,30 @@ describe('injectQuery', () => {
     test('should complete queries before whenStable() resolves', async () => {
       const app = TestBed.inject(ApplicationRef)
 
-      const query = TestBed.runInInjectionContext(() =>
-        injectQuery(() => ({
+      @Component({
+        selector: 'app-test',
+        template: '',
+        changeDetection: ChangeDetectionStrategy.OnPush,
+      })
+      class TestComponent {
+        query = injectQuery(() => ({
           queryKey: ['pendingTasksTest'],
           queryFn: async () => {
             await sleep(50)
             return 'test data'
           },
-        })),
-      )
+        }))
+      }
+
+      const fixture = TestBed.createComponent(TestComponent)
+      fixture.detectChanges()
+      const query = fixture.componentInstance.query
 
       expect(query.status()).toBe('pending')
       expect(query.data()).toBeUndefined()
 
-      const stablePromise = app.whenStable()
       await vi.advanceTimersByTimeAsync(60)
-      await stablePromise
+      await app.whenStable()
 
       expect(query.status()).toBe('success')
       expect(query.data()).toBe('test data')
@@ -602,14 +1014,25 @@ describe('injectQuery', () => {
       const httpClient = TestBed.inject(HttpClient)
       const httpTestingController = TestBed.inject(HttpTestingController)
 
-      // Create a query using HttpClient
-      const query = TestBed.runInInjectionContext(() =>
-        injectQuery(() => ({
+      @Component({
+        selector: 'app-test',
+        template: '',
+        changeDetection: ChangeDetectionStrategy.OnPush,
+      })
+      class TestComponent {
+        httpClient = httpClient
+        query = injectQuery(() => ({
           queryKey: ['httpClientTest'],
           queryFn: () =>
-            lastValueFrom(httpClient.get<{ message: string }>('/api/test')),
-        })),
-      )
+            lastValueFrom(
+              this.httpClient.get<{ message: string }>('/api/test'),
+            ),
+        }))
+      }
+
+      const fixture = TestBed.createComponent(TestComponent)
+      fixture.detectChanges()
+      const query = fixture.componentInstance.query
 
       // Schedule the HTTP response
       setTimeout(() => {
@@ -621,9 +1044,8 @@ describe('injectQuery', () => {
       expect(query.status()).toBe('pending')
 
       // Advance timers and wait for Angular to be "stable"
-      const stablePromise = app.whenStable()
       await vi.advanceTimersByTimeAsync(20)
-      await stablePromise
+      await app.whenStable()
 
       // Query should be complete after whenStable() thanks to PendingTasks integration
       expect(query.status()).toBe('success')
@@ -642,28 +1064,36 @@ describe('injectQuery', () => {
       })
 
       const app = TestBed.inject(ApplicationRef)
-      let callCount = 0
 
-      const query = TestBed.runInInjectionContext(() =>
-        injectQuery(() => ({
+      @Component({
+        selector: 'app-test',
+        template: '',
+        changeDetection: ChangeDetectionStrategy.OnPush,
+      })
+      class TestComponent {
+        callCount = 0
+        query = injectQuery(() => ({
           queryKey: ['sync-stale'],
           staleTime: 1000,
           queryFn: () => {
-            callCount++
-            return `sync-data-${callCount}`
+            this.callCount++
+            return `sync-data-${this.callCount}`
           },
-        })),
-      )
+        }))
+      }
 
-      // Synchronize pending effects
-      TestBed.tick()
+      const fixture = TestBed.createComponent(TestComponent)
+      fixture.detectChanges()
+      const component = fixture.componentInstance
+      const query = component.query
 
       const stablePromise = app.whenStable()
+      await vi.advanceTimersToNextTimerAsync()
       await stablePromise
 
       expect(query.status()).toBe('success')
       expect(query.data()).toBe('sync-data-1')
-      expect(callCount).toBe(1)
+      expect(component.callCount).toBe(1)
 
       await query.refetch()
       await Promise.resolve()
@@ -672,7 +1102,7 @@ describe('injectQuery', () => {
 
       expect(query.status()).toBe('success')
       expect(query.data()).toBe('sync-data-2')
-      expect(callCount).toBe(2)
+      expect(component.callCount).toBe(2)
     })
 
     test('should handle enabled/disabled transitions with synchronous queryFn', async () => {
@@ -686,34 +1116,48 @@ describe('injectQuery', () => {
 
       const app = TestBed.inject(ApplicationRef)
       const enabledSignal = signal(false)
-      let callCount = 0
 
-      const query = TestBed.runInInjectionContext(() =>
-        injectQuery(() => ({
+      @Component({
+        selector: 'app-test',
+        template: '',
+        changeDetection: ChangeDetectionStrategy.OnPush,
+      })
+      class TestComponent {
+        enabledSignal = enabledSignal
+        callCount = 0
+        query = injectQuery(() => ({
           queryKey: ['sync-enabled'],
-          enabled: enabledSignal(),
+          enabled: this.enabledSignal(),
           queryFn: () => {
-            callCount++
-            return `sync-data-${callCount}`
+            this.callCount++
+            return `sync-data-${this.callCount}`
           },
-        })),
-      )
+        }))
+      }
+
+      const fixture = TestBed.createComponent(TestComponent)
+      fixture.detectChanges()
+      const component = fixture.componentInstance
+      const query = component.query
 
       // Initially disabled
-      TestBed.tick()
+      await vi.advanceTimersByTimeAsync(0)
       await app.whenStable()
       expect(query.status()).toBe('pending')
       expect(query.data()).toBeUndefined()
-      expect(callCount).toBe(0)
+      expect(component.callCount).toBe(0)
 
       // Enable the query
       enabledSignal.set(true)
-      TestBed.tick()
+      fixture.detectChanges()
+
+      const stablePromise = app.whenStable()
+      await vi.advanceTimersToNextTimerAsync()
+      await stablePromise
 
-      await app.whenStable()
       expect(query.status()).toBe('success')
       expect(query.data()).toBe('sync-data-1')
-      expect(callCount).toBe(1)
+      expect(component.callCount).toBe(1)
     })
 
     test('should handle query invalidation with synchronous data', async () => {
@@ -727,39 +1171,47 @@ describe('injectQuery', () => {
 
       const app = TestBed.inject(ApplicationRef)
       const testKey = ['sync-invalidate']
-      let callCount = 0
 
-      const query = TestBed.runInInjectionContext(() =>
-        injectQuery(() => ({
+      @Component({
+        selector: 'app-test',
+        template: '',
+        changeDetection: ChangeDetectionStrategy.OnPush,
+      })
+      class TestComponent {
+        callCount = 0
+        query = injectQuery(() => ({
           queryKey: testKey,
           queryFn: () => {
-            callCount++
-            return `sync-data-${callCount}`
+            this.callCount++
+            return `sync-data-${this.callCount}`
           },
-        })),
-      )
+        }))
+      }
 
-      // Synchronize pending effects
-      TestBed.tick()
+      const fixture = TestBed.createComponent(TestComponent)
+      fixture.detectChanges()
+      const component = fixture.componentInstance
+      const query = component.query
+
+      const stablePromise = app.whenStable()
+      await vi.advanceTimersToNextTimerAsync()
+      await stablePromise
 
-      await app.whenStable()
       expect(query.status()).toBe('success')
       expect(query.data()).toBe('sync-data-1')
-      expect(callCount).toBe(1)
+      expect(component.callCount).toBe(1)
 
       // Invalidate the query
       queryClient.invalidateQueries({ queryKey: testKey })
-      TestBed.tick()
 
       // Wait for the invalidation to trigger a refetch
       await Promise.resolve()
       await vi.advanceTimersByTimeAsync(10)
-      TestBed.tick()
 
       await app.whenStable()
       expect(query.status()).toBe('success')
       expect(query.data()).toBe('sync-data-2')
-      expect(callCount).toBe(2)
+      expect(component.callCount).toBe(2)
     })
   })
 })
diff --git a/packages/angular-query-experimental/src/__tests__/mutation-options.test.ts b/packages/angular-query-experimental/src/__tests__/mutation-options.test.ts
index ab040037d5..553df12d36 100644
--- a/packages/angular-query-experimental/src/__tests__/mutation-options.test.ts
+++ b/packages/angular-query-experimental/src/__tests__/mutation-options.test.ts
@@ -1,5 +1,4 @@
 import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
-import { provideZonelessChangeDetection } from '@angular/core'
 import { TestBed } from '@angular/core/testing'
 import { QueryClient } from '@tanstack/query-core'
 import { sleep } from '@tanstack/query-test-utils'
@@ -8,8 +7,8 @@ import {
   injectMutation,
   injectMutationState,
   mutationOptions,
-  provideTanStackQuery,
 } from '..'
+import { flushQueryUpdates, setupTanStackQueryTestBed } from './test-utils'
 
 describe('mutationOptions', () => {
   let queryClient: QueryClient
@@ -17,12 +16,7 @@ describe('mutationOptions', () => {
   beforeEach(() => {
     vi.useFakeTimers()
     queryClient = new QueryClient()
-    TestBed.configureTestingModule({
-      providers: [
-        provideZonelessChangeDetection(),
-        provideTanStackQuery(queryClient),
-      ],
-    })
+    setupTanStackQueryTestBed(queryClient)
   })
 
   afterEach(() => {
@@ -61,7 +55,7 @@ describe('mutationOptions', () => {
 
     mutation.mutate()
     expect(isMutating()).toBe(0)
-    await vi.advanceTimersByTimeAsync(0)
+    await flushQueryUpdates()
     expect(isMutating()).toBe(1)
     await vi.advanceTimersByTimeAsync(51)
     expect(isMutating()).toBe(0)
@@ -81,7 +75,7 @@ describe('mutationOptions', () => {
 
     mutation.mutate()
     expect(isMutating()).toBe(0)
-    await vi.advanceTimersByTimeAsync(0)
+    await flushQueryUpdates()
     expect(isMutating()).toBe(1)
     await vi.advanceTimersByTimeAsync(51)
     expect(isMutating()).toBe(0)
@@ -109,7 +103,7 @@ describe('mutationOptions', () => {
     mutation1.mutate()
     mutation2.mutate()
     expect(isMutating()).toBe(0)
-    await vi.advanceTimersByTimeAsync(0)
+    await flushQueryUpdates()
     expect(isMutating()).toBe(2)
     await vi.advanceTimersByTimeAsync(51)
     expect(isMutating()).toBe(0)
@@ -137,7 +131,7 @@ describe('mutationOptions', () => {
     mutation1.mutate()
     mutation2.mutate()
     expect(isMutating()).toBe(0)
-    await vi.advanceTimersByTimeAsync(0)
+    await flushQueryUpdates()
     expect(isMutating()).toBe(1)
     await vi.advanceTimersByTimeAsync(51)
     expect(isMutating()).toBe(0)
diff --git a/packages/angular-query-experimental/src/__tests__/pending-tasks-ssr-queries.test.ts b/packages/angular-query-experimental/src/__tests__/pending-tasks-ssr-queries.test.ts
new file mode 100644
index 0000000000..86d1afe23c
--- /dev/null
+++ b/packages/angular-query-experimental/src/__tests__/pending-tasks-ssr-queries.test.ts
@@ -0,0 +1,75 @@
+import {
+  ChangeDetectionStrategy,
+  Component,
+  destroyPlatform,
+  provideZonelessChangeDetection,
+} from '@angular/core'
+import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'
+import {
+  provideServerRendering,
+  renderApplication,
+} from '@angular/platform-server'
+import { bootstrapApplication } from '@angular/platform-browser'
+import { sleep } from '@tanstack/query-test-utils'
+import { QueryClient } from '@tanstack/query-core'
+import { injectQueries } from '../inject-queries'
+import { provideTanStackQuery } from '../providers'
+
+describe('PendingTasks SSR (injectQueries)', () => {
+  beforeEach(() => {
+    destroyPlatform()
+    vi.useFakeTimers()
+  })
+
+  afterEach(() => {
+    vi.useRealTimers()
+  })
+
+  @Component({
+    selector: 'app-root',
+    template: '{{ queries()[0].data() }}',
+    standalone: true,
+    changeDetection: ChangeDetectionStrategy.OnPush,
+  })
+  class TestComponent {
+    queries = injectQueries(() => ({
+      queries: [
+        {
+          queryKey: ['ssr-queries-test'],
+          queryFn: async () => {
+            await sleep(1000)
+            return 'queries-data-fetched-on-ssr'
+          },
+        },
+      ],
+    }))
+  }
+
+  test('should wait for stability of queries', async () => {
+    const htmlPromise = renderApplication(
+      () =>
+        bootstrapApplication(TestComponent, {
+          providers: [
+            provideServerRendering(),
+            provideZonelessChangeDetection(),
+            provideTanStackQuery(
+              new QueryClient({
+                defaultOptions: { queries: { retry: false } },
+              }),
+            ),
+          ],
+        }),
+      {
+        url: '/',
+        document:
+          '<!doctype html><html><body><app-root></app-root></body></html>',
+      },
+    )
+
+    await vi.runAllTimersAsync()
+    const html = await htmlPromise
+
+    expect(html).toContain('queries-data-fetched-on-ssr')
+  })
+})
+
diff --git a/packages/angular-query-experimental/src/__tests__/pending-tasks-ssr.test.ts b/packages/angular-query-experimental/src/__tests__/pending-tasks-ssr.test.ts
new file mode 100644
index 0000000000..40c972bc6f
--- /dev/null
+++ b/packages/angular-query-experimental/src/__tests__/pending-tasks-ssr.test.ts
@@ -0,0 +1,72 @@
+import {
+  ChangeDetectionStrategy,
+  Component,
+  destroyPlatform,
+  provideZonelessChangeDetection,
+} from '@angular/core'
+import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'
+
+import {
+  provideServerRendering,
+  renderApplication,
+} from '@angular/platform-server'
+import { bootstrapApplication } from '@angular/platform-browser'
+
+import { sleep } from '@tanstack/query-test-utils'
+import { QueryClient } from '@tanstack/query-core'
+import { injectQuery } from '../inject-query'
+import { provideTanStackQuery } from '../providers'
+
+describe('PendingTasks SSR', () => {
+  beforeEach(() => {
+    destroyPlatform()
+    vi.useFakeTimers()
+  })
+
+  afterEach(() => {
+    vi.useRealTimers()
+  })
+
+  @Component({
+    selector: 'app-root',
+    template: '{{ query.data() }}',
+    standalone: true,
+    changeDetection: ChangeDetectionStrategy.OnPush,
+  })
+  class TestComponent {
+    query = injectQuery(() => ({
+      queryKey: ['ssr-test'],
+      queryFn: async () => {
+        await sleep(1000)
+        return 'data-fetched-on-ssr'
+      },
+    }))
+  }
+
+  test('should wait for stability of queries', async () => {
+    const htmlPromise = renderApplication(
+      () =>
+        bootstrapApplication(TestComponent, {
+          providers: [
+            provideServerRendering(),
+            provideZonelessChangeDetection(),
+            provideTanStackQuery(
+              new QueryClient({
+                defaultOptions: { queries: { retry: false } },
+              }),
+            ),
+          ],
+        }),
+      {
+        url: '/',
+        document:
+          '<!doctype html><html><body><app-root></app-root></body></html>',
+      },
+    )
+
+    await vi.runAllTimersAsync()
+    const html = await htmlPromise
+
+    expect(html).toContain('data-fetched-on-ssr')
+  })
+})
diff --git a/packages/angular-query-experimental/src/__tests__/pending-tasks.test.ts b/packages/angular-query-experimental/src/__tests__/pending-tasks.test.ts
index 92f70aed9f..5448bbbcac 100644
--- a/packages/angular-query-experimental/src/__tests__/pending-tasks.test.ts
+++ b/packages/angular-query-experimental/src/__tests__/pending-tasks.test.ts
@@ -1,7 +1,7 @@
 import {
   ApplicationRef,
+  ChangeDetectionStrategy,
   Component,
-  provideZonelessChangeDetection,
 } from '@angular/core'
 import { TestBed } from '@angular/core/testing'
 import { HttpClient, provideHttpClient } from '@angular/common/http'
@@ -12,13 +12,8 @@ import {
 import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'
 import { sleep } from '@tanstack/query-test-utils'
 import { lastValueFrom } from 'rxjs'
-import {
-  QueryClient,
-  injectMutation,
-  injectQuery,
-  onlineManager,
-  provideTanStackQuery,
-} from '..'
+import { QueryClient, injectMutation, injectQuery, onlineManager } from '..'
+import { flushQueryUpdates, setupTanStackQueryTestBed } from './test-utils'
 
 describe('PendingTasks Integration', () => {
   let queryClient: QueryClient
@@ -37,12 +32,7 @@ describe('PendingTasks Integration', () => {
       },
     })
 
-    TestBed.configureTestingModule({
-      providers: [
-        provideZonelessChangeDetection(),
-        provideTanStackQuery(queryClient),
-      ],
-    })
+    setupTanStackQueryTestBed(queryClient)
   })
 
   afterEach(() => {
@@ -55,12 +45,21 @@ describe('PendingTasks Integration', () => {
     test('should handle synchronous queryFn with whenStable()', async () => {
       const app = TestBed.inject(ApplicationRef)
 
-      const query = TestBed.runInInjectionContext(() =>
-        injectQuery(() => ({
+      @Component({
+        selector: 'app-test',
+        template: '',
+        changeDetection: ChangeDetectionStrategy.OnPush,
+      })
+      class TestComponent {
+        query = injectQuery(() => ({
           queryKey: ['sync'],
           queryFn: () => 'instant-data', // Resolves synchronously
-        })),
-      )
+        }))
+      }
+
+      const fixture = TestBed.createComponent(TestComponent)
+      fixture.detectChanges()
+      const query = fixture.componentInstance.query
 
       // Should start as pending even with synchronous data
       expect(query.status()).toBe('pending')
@@ -140,7 +139,6 @@ describe('PendingTasks Integration', () => {
       )
 
       mutation.mutate()
-
       TestBed.tick()
 
       const stablePromise = app.whenStable()
@@ -183,18 +181,27 @@ describe('PendingTasks Integration', () => {
 
     test('should handle rapid refetches without task leaks', async () => {
       const app = TestBed.inject(ApplicationRef)
-      let callCount = 0
 
-      const query = TestBed.runInInjectionContext(() =>
-        injectQuery(() => ({
+      @Component({
+        selector: 'app-test',
+        template: '',
+        changeDetection: ChangeDetectionStrategy.OnPush,
+      })
+      class TestComponent {
+        callCount = 0
+        query = injectQuery(() => ({
           queryKey: ['rapid-refetch'],
           queryFn: async () => {
-            callCount++
+            this.callCount++
             await sleep(10)
-            return `data-${callCount}`
+            return `data-${this.callCount}`
           },
-        })),
-      )
+        }))
+      }
+
+      const fixture = TestBed.createComponent(TestComponent)
+      fixture.detectChanges()
+      const query = fixture.componentInstance.query
 
       // Trigger multiple rapid refetches
       query.refetch()
@@ -209,6 +216,54 @@ describe('PendingTasks Integration', () => {
       expect(query.data()).toMatch(/^data-\d+$/)
     })
 
+    test('should keep PendingTasks active when query starts offline (never reaches fetching)', async () => {
+      const app = TestBed.inject(ApplicationRef)
+
+      onlineManager.setOnline(false)
+
+      const query = TestBed.runInInjectionContext(() =>
+        injectQuery(() => ({
+          queryKey: ['start-offline'],
+          networkMode: 'online', // Default: won't fetch while offline
+          queryFn: async () => {
+            await sleep(10)
+            return 'online-data'
+          },
+        })),
+      )
+
+      // Allow query to initialize
+      await Promise.resolve()
+      await flushQueryUpdates()
+
+      // Query should initialize directly to 'paused' (never goes through 'fetching')
+      expect(query.status()).toBe('pending')
+      expect(query.fetchStatus()).toBe('paused')
+
+      const stablePromise = app.whenStable()
+      let stableResolved = false
+      void stablePromise.then(() => {
+        stableResolved = true
+      })
+
+      await Promise.resolve()
+
+      // PendingTasks should block stability even though we never hit 'fetching'
+      expect(stableResolved).toBe(false)
+
+      // Bring the app back online so the query can fetch
+      onlineManager.setOnline(true)
+
+      await vi.advanceTimersByTimeAsync(20)
+      await Promise.resolve()
+
+      await stablePromise
+
+      expect(stableResolved).toBe(true)
+      expect(query.status()).toBe('success')
+      expect(query.data()).toBe('online-data')
+    })
+
     test('should keep PendingTasks active while query retry is paused offline', async () => {
       const app = TestBed.inject(ApplicationRef)
       let attempt = 0
@@ -230,7 +285,7 @@ describe('PendingTasks Integration', () => {
       )
 
       // Allow the initial attempt to start and fail
-      await vi.advanceTimersByTimeAsync(0)
+      await flushQueryUpdates()
       await Promise.resolve()
 
       // Wait for the first attempt to complete and start retry delay
@@ -279,6 +334,7 @@ describe('PendingTasks Integration', () => {
   describe('Component Destruction', () => {
     @Component({
       template: '',
+      changeDetection: ChangeDetectionStrategy.OnPush,
     })
     class TestComponent {
       query = injectQuery(() => ({
@@ -298,36 +354,42 @@ describe('PendingTasks Integration', () => {
     }
 
     test('should cleanup pending tasks when component with active query is destroyed', async () => {
-      const app = TestBed.inject(ApplicationRef)
       const fixture = TestBed.createComponent(TestComponent)
+      fixture.detectChanges()
 
       // Start the query
       expect(fixture.componentInstance.query.status()).toBe('pending')
+      expect(fixture.isStable()).toBe(false)
 
       // Destroy component while query is running
       fixture.destroy()
 
       // Angular should become stable even though component was destroyed
-      const stablePromise = app.whenStable()
+      const stablePromise = fixture.whenStable()
       await vi.advanceTimersByTimeAsync(150)
-
-      await expect(stablePromise).resolves.toEqual(undefined)
+      await stablePromise
+      expect(fixture.isStable()).toBe(true)
     })
 
     test('should cleanup pending tasks when component with active mutation is destroyed', async () => {
-      const app = TestBed.inject(ApplicationRef)
       const fixture = TestBed.createComponent(TestComponent)
+      fixture.detectChanges()
 
       fixture.componentInstance.mutation.mutate('test')
+      fixture.detectChanges()
+      expect(fixture.isStable()).toBe(false)
 
       // Destroy component while mutation is running
       fixture.destroy()
+      fixture.detectChanges()
+      expect(fixture.isStable()).toBe(true)
 
       // Angular should become stable even though component was destroyed
-      const stablePromise = app.whenStable()
-      await vi.advanceTimersByTimeAsync(150)
+      const stablePromise = fixture.whenStable()
+      await vi.advanceTimersByTimeAsync(200)
+      await stablePromise
 
-      await expect(stablePromise).resolves.toEqual(undefined)
+      expect(fixture.isStable()).toBe(true)
     })
   })
 
@@ -335,32 +397,37 @@ describe('PendingTasks Integration', () => {
     test('should handle multiple queries running simultaneously', async () => {
       const app = TestBed.inject(ApplicationRef)
 
-      const query1 = TestBed.runInInjectionContext(() =>
-        injectQuery(() => ({
+      @Component({
+        selector: 'app-test',
+        template: '',
+        changeDetection: ChangeDetectionStrategy.OnPush,
+      })
+      class TestComponent {
+        query1 = injectQuery(() => ({
           queryKey: ['concurrent-1'],
           queryFn: async () => {
             await sleep(30)
             return 'data-1'
           },
-        })),
-      )
+        }))
 
-      const query2 = TestBed.runInInjectionContext(() =>
-        injectQuery(() => ({
+        query2 = injectQuery(() => ({
           queryKey: ['concurrent-2'],
           queryFn: async () => {
             await sleep(50)
             return 'data-2'
           },
-        })),
-      )
+        }))
 
-      const query3 = TestBed.runInInjectionContext(() =>
-        injectQuery(() => ({
+        query3 = injectQuery(() => ({
           queryKey: ['concurrent-3'],
           queryFn: () => 'instant-data', // Synchronous
-        })),
-      )
+        }))
+      }
+
+      const fixture = TestBed.createComponent(TestComponent)
+      fixture.detectChanges()
+      const { query1, query2, query3 } = fixture.componentInstance
 
       // All queries should start
       expect(query1.status()).toBe('pending')
@@ -469,14 +536,8 @@ describe('PendingTasks Integration', () => {
 
   describe('HttpClient Integration', () => {
     beforeEach(() => {
-      TestBed.resetTestingModule()
-      TestBed.configureTestingModule({
-        providers: [
-          provideZonelessChangeDetection(),
-          provideTanStackQuery(queryClient),
-          provideHttpClient(),
-          provideHttpClientTesting(),
-        ],
+      setupTanStackQueryTestBed(queryClient, {
+        providers: [provideHttpClient(), provideHttpClientTesting()],
       })
     })
 
diff --git a/packages/angular-query-experimental/src/__tests__/signal-proxy.test.ts b/packages/angular-query-experimental/src/__tests__/signal-proxy.test.ts
index d06aef6723..1e039d33f4 100644
--- a/packages/angular-query-experimental/src/__tests__/signal-proxy.test.ts
+++ b/packages/angular-query-experimental/src/__tests__/signal-proxy.test.ts
@@ -1,10 +1,21 @@
-import { isSignal, signal } from '@angular/core'
-import { describe, expect, test } from 'vitest'
+import {
+  ChangeDetectionStrategy,
+  Component,
+  computed,
+  input,
+  isSignal,
+  provideZonelessChangeDetection,
+  signal,
+  untracked,
+} from '@angular/core'
+import { beforeEach, describe, expect, test } from 'vitest'
+import { TestBed } from '@angular/core/testing'
 import { signalProxy } from '../signal-proxy'
+import { registerSignalInput } from './test-utils'
 
 describe('signalProxy', () => {
   const inputSignal = signal({ fn: () => 'bar', baz: 'qux' })
-  const proxy = signalProxy(inputSignal)
+  const proxy = signalProxy(inputSignal, ['fn'])
 
   test('should have computed fields', () => {
     expect(proxy.baz()).toEqual('qux')
@@ -24,4 +35,63 @@ describe('signalProxy', () => {
   test('supports "Object.keys"', () => {
     expect(Object.keys(proxy)).toEqual(['fn', 'baz'])
   })
+
+  describe('in component fixture', () => {
+    @Component({
+      selector: 'app-test',
+      template: '{{ proxy.baz() }}',
+      changeDetection: ChangeDetectionStrategy.OnPush,
+    })
+    class TestComponent {
+      number = input.required<number>()
+      obj = computed(() => ({
+        number: this.number(),
+        fn: () => untracked(this.number) + 1,
+      }))
+      proxy = signalProxy(this.obj, ['fn'])
+      shortNumber = this.proxy.number
+      shortFn = this.proxy.fn
+    }
+    registerSignalInput(TestComponent, 'number')
+
+    beforeEach(() => {
+      TestBed.configureTestingModule({
+        providers: [provideZonelessChangeDetection()],
+      })
+    })
+
+    test('should generate fixed fields after initial change detection run', () => {
+      const fixture = TestBed.createComponent(TestComponent)
+      const instance = fixture.componentInstance
+
+      expect(() => instance.shortNumber).not.throw()
+      expect(() => instance.shortNumber()).toThrow()
+
+      fixture.componentRef.setInput('number', 1)
+      fixture.detectChanges()
+
+      expect(isSignal(instance.proxy.number)).toBe(true)
+      expect(instance.proxy.number()).toBe(1)
+      expect(instance.shortNumber).toBe(instance.proxy.number)
+
+      expect(instance.proxy.fn()).toBe(2)
+      expect(isSignal(instance.proxy.fn)).toBe(false)
+      expect(instance.shortFn).toBe(instance.proxy.fn)
+    })
+
+    test('should reflect updates on the proxy', () => {
+      const fixture = TestBed.createComponent(TestComponent)
+      const instance = fixture.componentInstance
+      fixture.componentRef.setInput('number', 0)
+      fixture.detectChanges()
+
+      expect(instance.shortNumber()).toBe(0)
+      expect(instance.shortFn()).toBe(1)
+
+      fixture.componentRef.setInput('number', 1)
+
+      expect(instance.shortNumber()).toBe(1)
+      expect(instance.shortFn()).toBe(2)
+    })
+  })
 })
diff --git a/packages/angular-query-experimental/src/__tests__/test-utils.ts b/packages/angular-query-experimental/src/__tests__/test-utils.ts
index 218cdea5f6..879dda82b6 100644
--- a/packages/angular-query-experimental/src/__tests__/test-utils.ts
+++ b/packages/angular-query-experimental/src/__tests__/test-utils.ts
@@ -1,8 +1,20 @@
-import { isSignal, untracked } from '@angular/core'
-import { SIGNAL, signalSetFn } from '@angular/core/primitives/signals'
-import { expect } from 'vitest'
-import type { InputSignal, Signal } from '@angular/core'
-import type { ComponentFixture } from '@angular/core/testing'
+import {
+  isSignal,
+  provideZonelessChangeDetection,
+  untracked,
+} from '@angular/core'
+import { TestBed } from '@angular/core/testing'
+import { expect, vi } from 'vitest'
+import { provideTanStackQuery } from '..'
+import type { QueryClient } from '@tanstack/query-core'
+import type {
+  EnvironmentProviders,
+  Provider,
+  Signal,
+  Type,
+} from '@angular/core'
+
+// cspell:ignore ɵcmp ɵdir
 
 // Evaluate all signals on an object and return the result
 function evaluateSignals<T extends Record<string, any>>(
@@ -35,43 +47,56 @@ export const expectSignals = <T extends Record<string, any>>(
   expect(evaluateSignals(obj)).toMatchObject(expected)
 }
 
-type ToSignalInputUpdatableMap<T> = {
-  [K in keyof T as T[K] extends InputSignal<any>
-    ? K
-    : never]: T[K] extends InputSignal<infer Value> ? Value : never
+/**
+ * Reset Angular's TestBed and configure the standard TanStack Query providers for tests.
+ * Pass additional providers (including EnvironmentProviders) via the options argument.
+ */
+export function setupTanStackQueryTestBed(
+  queryClient: QueryClient,
+  options: { providers?: Array<Provider | EnvironmentProviders> } = {},
+) {
+  TestBed.resetTestingModule()
+  TestBed.configureTestingModule({
+    providers: [
+      provideZonelessChangeDetection(),
+      provideTanStackQuery(queryClient),
+      ...(options.providers ?? []),
+    ],
+  })
 }
 
-function componentHasSignalInputProperty<TProperty extends string>(
-  component: object,
-  property: TProperty,
-): component is { [key in TProperty]: InputSignal<unknown> } {
-  return (
-    component.hasOwnProperty(property) && (component as any)[property][SIGNAL]
-  )
+/**
+ * TanStack Query schedules notifyManager updates with setTimeout(0); when fake timers
+ * are enabled, advance them so PendingTasks sees the queued work.
+ */
+export async function flushQueryUpdates() {
+  await vi.advanceTimersByTimeAsync(0)
 }
 
+const SIGNAL_BASED_INPUT_FLAG = 1
+
 /**
- * Set required signal input value to component fixture
- * @see https://github.com/angular/angular/issues/54013
+ * Register a signal-based input on a test-only component/dir so Angular marks the
+ * `input.required()` member as bound before the initial change detection run.
+ *
+ * After migrating to Angular 21 we can use the CLI to compile and run Vitest tests
+ * and this helper should be obsolete.
  */
-export function setSignalInputs<T extends NonNullable<unknown>>(
-  component: T,
-  inputs: ToSignalInputUpdatableMap<T>,
+export function registerSignalInput<T>(
+  type: Type<T>,
+  inputName: keyof T & string,
 ) {
-  for (const inputKey in inputs) {
-    if (componentHasSignalInputProperty(component, inputKey)) {
-      signalSetFn(component[inputKey][SIGNAL], inputs[inputKey])
-    }
+  const definition = (type as any).ɵcmp ?? (type as any).ɵdir
+  if (!definition) {
+    throw new Error(`Component ${type.name} is missing its definition`)
   }
-}
 
-export function setFixtureSignalInputs<T extends NonNullable<unknown>>(
-  componentFixture: ComponentFixture<T>,
-  inputs: ToSignalInputUpdatableMap<T>,
-  options: { detectChanges: boolean } = { detectChanges: true },
-) {
-  setSignalInputs(componentFixture.componentInstance, inputs)
-  if (options.detectChanges) {
-    componentFixture.detectChanges()
+  definition.inputs = {
+    ...(definition.inputs ?? {}),
+    [inputName]: [inputName, SIGNAL_BASED_INPUT_FLAG, null],
+  }
+  definition.declaredInputs = {
+    ...(definition.declaredInputs ?? {}),
+    [inputName]: inputName,
   }
 }
diff --git a/packages/angular-query-experimental/src/__tests__/with-devtools.test.ts b/packages/angular-query-experimental/src/__tests__/with-devtools.test.ts
index 6c6e128115..5699d34151 100644
--- a/packages/angular-query-experimental/src/__tests__/with-devtools.test.ts
+++ b/packages/angular-query-experimental/src/__tests__/with-devtools.test.ts
@@ -13,6 +13,7 @@ import {
 } from '@angular/core'
 import { provideTanStackQuery } from '../providers'
 import { withDevtools } from '../devtools'
+import { flushQueryUpdates } from './test-utils'
 import type {
   DevtoolsButtonPosition,
   DevtoolsErrorType,
@@ -138,7 +139,7 @@ describe('withDevtools feature', () => {
       })
 
       TestBed.inject(ENVIRONMENT_INITIALIZER)
-      await vi.advanceTimersByTimeAsync(0)
+      await flushQueryUpdates()
       TestBed.tick()
       await vi.dynamicImportSettled()
       TestBed.tick()
@@ -169,7 +170,7 @@ describe('withDevtools feature', () => {
     TestBed.inject(ENVIRONMENT_INITIALIZER)
     // Destroys injector
     TestBed.resetTestingModule()
-    await vi.advanceTimersByTimeAsync(0)
+    await flushQueryUpdates()
     await vi.dynamicImportSettled()
 
     expect(mockTanstackQueryDevtools).not.toHaveBeenCalled()
@@ -189,8 +190,7 @@ describe('withDevtools feature', () => {
     })
 
     TestBed.inject(ENVIRONMENT_INITIALIZER)
-    await vi.advanceTimersByTimeAsync(0)
-    await vi.dynamicImportSettled()
+    await flushQueryUpdates()
 
     expect(mockTanstackQueryDevtools).toHaveBeenCalledTimes(1)
 
@@ -206,7 +206,7 @@ describe('withDevtools feature', () => {
     )
 
     TestBed.inject(ENVIRONMENT_INITIALIZER)
-    await vi.advanceTimersByTimeAsync(0)
+    await flushQueryUpdates()
 
     expect(mockTanstackQueryDevtools).toHaveBeenCalledTimes(1)
   })
@@ -251,8 +251,7 @@ describe('withDevtools feature', () => {
     })
 
     TestBed.inject(ENVIRONMENT_INITIALIZER)
-    await vi.advanceTimersByTimeAsync(0)
-    await vi.dynamicImportSettled()
+    await flushQueryUpdates()
 
     TestBed.tick()
 
@@ -292,8 +291,7 @@ describe('withDevtools feature', () => {
     })
 
     TestBed.inject(ENVIRONMENT_INITIALIZER)
-    await vi.advanceTimersByTimeAsync(0)
-    await vi.dynamicImportSettled()
+    await flushQueryUpdates()
 
     TestBed.tick()
 
@@ -325,8 +323,7 @@ describe('withDevtools feature', () => {
     })
 
     TestBed.inject(ENVIRONMENT_INITIALIZER)
-    await vi.advanceTimersByTimeAsync(0)
-    await vi.dynamicImportSettled()
+    await flushQueryUpdates()
 
     TestBed.tick()
 
@@ -357,8 +354,7 @@ describe('withDevtools feature', () => {
     })
 
     TestBed.inject(ENVIRONMENT_INITIALIZER)
-    await vi.advanceTimersByTimeAsync(0)
-    await vi.dynamicImportSettled()
+    await flushQueryUpdates()
 
     TestBed.tick()
 
@@ -391,8 +387,7 @@ describe('withDevtools feature', () => {
     })
 
     TestBed.inject(ENVIRONMENT_INITIALIZER)
-    await vi.advanceTimersByTimeAsync(0)
-    await vi.dynamicImportSettled()
+    await flushQueryUpdates()
 
     TestBed.tick()
 
@@ -422,8 +417,7 @@ describe('withDevtools feature', () => {
     })
 
     TestBed.inject(ENVIRONMENT_INITIALIZER)
-    await vi.advanceTimersByTimeAsync(0)
-    await vi.dynamicImportSettled()
+    await flushQueryUpdates()
 
     expect(mockDevtoolsInstance.mount).toHaveBeenCalledTimes(1)
     expect(mockDevtoolsInstance.unmount).toHaveBeenCalledTimes(0)
@@ -449,7 +443,7 @@ describe('withDevtools feature', () => {
     })
 
     TestBed.inject(ENVIRONMENT_INITIALIZER)
-    await vi.advanceTimersByTimeAsync(0)
+    await flushQueryUpdates()
     TestBed.tick()
     await vi.dynamicImportSettled()
 
@@ -479,7 +473,7 @@ describe('withDevtools feature', () => {
     })
 
     TestBed.inject(ENVIRONMENT_INITIALIZER)
-    await vi.advanceTimersByTimeAsync(0)
+    await flushQueryUpdates()
 
     expect(mockTanstackQueryDevtools).not.toHaveBeenCalled()
     expect(mockDevtoolsInstance.mount).not.toHaveBeenCalled()
@@ -536,7 +530,7 @@ describe('withDevtools feature', () => {
       })
 
       TestBed.inject(ENVIRONMENT_INITIALIZER)
-      await vi.advanceTimersByTimeAsync(0)
+      await flushQueryUpdates()
 
       expect(withDevtoolsFn).toHaveBeenCalledWith(mockService1, mockService2)
     })
@@ -557,7 +551,7 @@ describe('withDevtools feature', () => {
       })
 
       TestBed.inject(ENVIRONMENT_INITIALIZER)
-      await vi.advanceTimersByTimeAsync(0)
+      await flushQueryUpdates()
 
       expect(withDevtoolsFn).toHaveBeenCalledWith()
     })
@@ -587,7 +581,7 @@ describe('withDevtools feature', () => {
       })
 
       TestBed.inject(ENVIRONMENT_INITIALIZER)
-      await vi.advanceTimersByTimeAsync(0)
+      await flushQueryUpdates()
 
       const service = TestBed.inject(ReactiveService)
 
diff --git a/packages/angular-query-experimental/src/__tests__/zonejs-adapter.test.ts b/packages/angular-query-experimental/src/__tests__/zonejs-adapter.test.ts
new file mode 100644
index 0000000000..6c4f52714a
--- /dev/null
+++ b/packages/angular-query-experimental/src/__tests__/zonejs-adapter.test.ts
@@ -0,0 +1,96 @@
+import 'zone.js'
+import {
+  ChangeDetectionStrategy,
+  Component,
+  provideZoneChangeDetection,
+} from '@angular/core'
+import { TestBed } from '@angular/core/testing'
+import { sleep } from '@tanstack/query-test-utils'
+import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
+import {
+  QueryClient,
+  injectMutation,
+  injectQuery,
+  provideTanStackQuery,
+} from '..'
+
+describe('adapter with Zone.js', () => {
+  let queryClient: QueryClient
+
+  beforeEach(() => {
+    vi.useFakeTimers({ shouldAdvanceTime: true })
+    queryClient = new QueryClient()
+
+    TestBed.resetTestingModule()
+    TestBed.configureTestingModule({
+      providers: [
+        provideZoneChangeDetection(),
+        provideTanStackQuery(queryClient),
+      ],
+    })
+  })
+
+  afterEach(() => {
+    vi.useRealTimers()
+  })
+
+  it('supports injectQuery in a Zone.js app', async () => {
+    @Component({
+      selector: 'zone-query-test',
+      template: '',
+      changeDetection: ChangeDetectionStrategy.OnPush,
+    })
+    class ZoneQueryTestComponent {
+      query = injectQuery(() => ({
+        queryKey: ['zone-query'],
+        queryFn: async () => {
+          await sleep(10)
+          return 'query-data'
+        },
+      }))
+    }
+
+    const fixture = TestBed.createComponent(ZoneQueryTestComponent)
+    fixture.detectChanges()
+
+    const query = fixture.componentInstance.query
+    expect(query.status()).toBe('pending')
+
+    const stablePromise = fixture.whenStable()
+    await vi.advanceTimersByTimeAsync(20)
+    await stablePromise
+
+    expect(query.status()).toBe('success')
+    expect(query.data()).toBe('query-data')
+  })
+
+  it('supports injectMutation in a Zone.js app', async () => {
+    @Component({
+      selector: 'zone-mutation-test',
+      template: '',
+      changeDetection: ChangeDetectionStrategy.OnPush,
+    })
+    class ZoneMutationTestComponent {
+      mutation = injectMutation(() => ({
+        mutationKey: ['zone-mutation'],
+        mutationFn: async (value: string) => {
+          await sleep(10)
+          return `mutated-${value}`
+        },
+      }))
+    }
+
+    const fixture = TestBed.createComponent(ZoneMutationTestComponent)
+    fixture.detectChanges()
+
+    const mutation = fixture.componentInstance.mutation
+    mutation.mutate('value')
+
+    const stablePromise = fixture.whenStable()
+    await vi.advanceTimersByTimeAsync(20)
+    await stablePromise
+
+    expect(mutation.status()).toBe('success')
+    expect(mutation.data()).toBe('mutated-value')
+  })
+})
diff --git a/packages/angular-query-experimental/src/create-base-query.ts b/packages/angular-query-experimental/src/create-base-query.ts
index 4daede7684..697fe7ae2b 100644
--- a/packages/angular-query-experimental/src/create-base-query.ts
+++ b/packages/angular-query-experimental/src/create-base-query.ts
@@ -1,10 +1,11 @@
 import {
+  DestroyRef,
   NgZone,
-  VERSION,
+  PendingTasks,
   computed,
   effect,
   inject,
-  signal,
+  linkedSignal,
   untracked,
 } from '@angular/core'
 import {
@@ -14,9 +15,9 @@ import {
 } from '@tanstack/query-core'
 import { signalProxy } from './signal-proxy'
 import { injectIsRestoring } from './inject-is-restoring'
-import { PENDING_TASKS } from './pending-tasks-compat'
-import type { PendingTaskRef } from './pending-tasks-compat'
+import type { MethodKeys } from './signal-proxy'
 import type {
+  DefaultedQueryObserverOptions,
   QueryKey,
   QueryObserver,
   QueryObserverResult,
@@ -27,6 +28,7 @@ import type { CreateBaseQueryOptions } from './types'
  * Base implementation for `injectQuery` and `injectInfiniteQuery`.
  * @param optionsFn
  * @param Observer
+ * @param excludeFunctions
  */
 export function createBaseQuery<
   TQueryFnData,
@@ -43,11 +45,29 @@ export function createBaseQuery<
     TQueryKey
   >,
   Observer: typeof QueryObserver,
+  excludeFunctions: ReadonlyArray<string>,
 ) {
   const ngZone = inject(NgZone)
-  const pendingTasks = inject(PENDING_TASKS)
+  const pendingTasks = inject(PendingTasks)
   const queryClient = inject(QueryClient)
   const isRestoring = injectIsRestoring()
+  const destroyRef = inject(DestroyRef)
+
+  let destroyed = false
+  let taskCleanupRef: (() => void) | null = null
+
+  const startPendingTask = () => {
+    if (!taskCleanupRef && !destroyed) {
+      taskCleanupRef = pendingTasks.add()
+    }
+  }
+
+  const stopPendingTask = () => {
+    if (taskCleanupRef) {
+      taskCleanupRef()
+      taskCleanupRef = null
+    }
+  }
 
   /**
    * Signal that has the default options from query client applied
@@ -63,113 +83,118 @@ export function createBaseQuery<
     return defaultedOptions
   })
 
-  const observerSignal = (() => {
-    let instance: QueryObserver<
+  // Computed without deps to lazy initialize the observer
+  const observerSignal = computed(() => {
+    return new Observer(queryClient, untracked(defaultedOptionsSignal))
+  })
+
+  effect(() => {
+    observerSignal().setOptions(defaultedOptionsSignal())
+  })
+
+  const trackObserverResult = (
+    result: QueryObserverResult<TData, TError>,
+    notifyOnChangeProps?: DefaultedQueryObserverOptions<
       TQueryFnData,
       TError,
       TData,
       TQueryData,
       TQueryKey
-    > | null = null
+    >['notifyOnChangeProps'],
+  ) => {
+    const observer = untracked(observerSignal)
+    const trackedResult = observer.trackResult(result)
+
+    if (!notifyOnChangeProps) {
+      autoTrackResultProperties(trackedResult)
+    }
+
+    return trackedResult
+  }
+
+  const autoTrackResultProperties = (
+    result: QueryObserverResult<TData, TError>,
+  ) => {
+    for (const key of Object.keys(result) as Array<
+      keyof QueryObserverResult<TData, TError>
+    >) {
+      if (key === 'promise') continue
+      const value = result[key]
+      if (typeof value === 'function') continue
+      // Access value once so QueryObserver knows this prop is tracked.
+      void value
+    }
+  }
+
+  const subscribeToObserver = () => {
+    const observer = untracked(observerSignal)
+    const initialState = observer.getCurrentResult()
+    if (initialState.fetchStatus !== 'idle') {
+      startPendingTask()
+    }
+
+    return observer.subscribe((state) => {
+      if (state.fetchStatus !== 'idle') {
+        startPendingTask()
+      } else {
+        stopPendingTask()
+      }
 
-    return computed(() => {
-      return (instance ||= new Observer(queryClient, defaultedOptionsSignal()))
+      queueMicrotask(() => {
+        if (destroyed) return
+        notifyManager.batch(() => {
+          ngZone.run(() => {
+            if (
+              state.isError &&
+              !state.isFetching &&
+              shouldThrowError(observer.options.throwOnError, [
+                state.error,
+                observer.getCurrentQuery(),
+              ])
+            ) {
+              ngZone.onError.emit(state.error)
+              throw state.error
+            }
+            const trackedState = trackObserverResult(
+              state,
+              observer.options.notifyOnChangeProps,
+            )
+            resultSignal.set(trackedState)
+          })
+        })
+      })
     })
-  })()
+  }
 
-  const optimisticResultSignal = computed(() =>
-    observerSignal().getOptimisticResult(defaultedOptionsSignal()),
-  )
-
-  const resultFromSubscriberSignal = signal<QueryObserverResult<
-    TData,
-    TError
-  > | null>(null)
-
-  effect(
-    (onCleanup) => {
-      const observer = observerSignal()
+  const resultSignal = linkedSignal({
+    source: defaultedOptionsSignal,
+    computation: () => {
+      const observer = untracked(observerSignal)
       const defaultedOptions = defaultedOptionsSignal()
 
-      untracked(() => {
-        observer.setOptions(defaultedOptions)
-      })
-      onCleanup(() => {
-        ngZone.run(() => resultFromSubscriberSignal.set(null))
-      })
+      const result = observer.getOptimisticResult(defaultedOptions)
+      return trackObserverResult(result, defaultedOptions.notifyOnChangeProps)
     },
-    {
-      // Set allowSignalWrites to support Angular < v19
-      // Set to undefined to avoid warning on newer versions
-      allowSignalWrites: VERSION.major < '19' || undefined,
-    },
-  )
+  })
 
   effect((onCleanup) => {
-    // observer.trackResult is not used as this optimization is not needed for Angular
-    const observer = observerSignal()
-    let pendingTaskRef: PendingTaskRef | null = null
-
-    const unsubscribe = isRestoring()
-      ? () => undefined
-      : untracked(() =>
-          ngZone.runOutsideAngular(() => {
-            return observer.subscribe(
-              notifyManager.batchCalls((state) => {
-                ngZone.run(() => {
-                  if (state.fetchStatus === 'fetching' && !pendingTaskRef) {
-                    pendingTaskRef = pendingTasks.add()
-                  }
-
-                  if (state.fetchStatus === 'idle' && pendingTaskRef) {
-                    pendingTaskRef()
-                    pendingTaskRef = null
-                  }
-
-                  if (
-                    state.isError &&
-                    !state.isFetching &&
-                    shouldThrowError(observer.options.throwOnError, [
-                      state.error,
-                      observer.getCurrentQuery(),
-                    ])
-                  ) {
-                    ngZone.onError.emit(state.error)
-                    throw state.error
-                  }
-                  resultFromSubscriberSignal.set(state)
-                })
-              }),
-            )
-          }),
-        )
-
+    if (isRestoring()) {
+      return
+    }
+    const unsubscribe = untracked(() => subscribeToObserver())
     onCleanup(() => {
-      if (pendingTaskRef) {
-        pendingTaskRef()
-        pendingTaskRef = null
-      }
       unsubscribe()
+      stopPendingTask()
     })
   })
 
+  destroyRef.onDestroy(() => {
+    destroyed = true
+    stopPendingTask()
+  })
+
   return signalProxy(
-    computed(() => {
-      const subscriberResult = resultFromSubscriberSignal()
-      const optimisticResult = optimisticResultSignal()
-      const result = subscriberResult ?? optimisticResult
-
-      // Wrap methods to ensure observer has latest options before execution
-      const observer = observerSignal()
-
-      const originalRefetch = result.refetch
-      return {
-        ...result,
-        refetch: ((...args: Parameters<typeof originalRefetch>) => {
-          observer.setOptions(defaultedOptionsSignal())
-          return originalRefetch(...args)
-        }) as typeof originalRefetch,
-      }
-    }),
+    resultSignal.asReadonly(),
+    excludeFunctions as Array<MethodKeys<QueryObserverResult<TData, TError>>>,
   )
 }
diff --git a/packages/angular-query-experimental/src/index.ts b/packages/angular-query-experimental/src/index.ts
index fc033224e5..18f7e3379b 100644
--- a/packages/angular-query-experimental/src/index.ts
+++ b/packages/angular-query-experimental/src/index.ts
@@ -39,7 +39,12 @@ export { injectMutation } from './inject-mutation'
 export type { InjectMutationStateOptions } from './inject-mutation-state'
 export { injectMutationState } from './inject-mutation-state'
 
-export type { QueriesOptions, QueriesResults } from './inject-queries'
+export type {
+  InjectQueriesOptions,
+  QueriesOptions,
+  QueriesResults,
+} from './inject-queries'
+export { injectQueries } from './inject-queries'
 
 export type { InjectQueryOptions } from './inject-query'
 export { injectQuery } from './inject-query'
diff --git a/packages/angular-query-experimental/src/inject-infinite-query.ts b/packages/angular-query-experimental/src/inject-infinite-query.ts
index ee6de03240..aa4a26cf4f 100644
--- a/packages/angular-query-experimental/src/inject-infinite-query.ts
+++ b/packages/angular-query-experimental/src/inject-infinite-query.ts
@@ -6,9 +6,11 @@ import {
   runInInjectionContext,
 } from '@angular/core'
 import { createBaseQuery } from './create-base-query'
+import type { MethodKeys } from './signal-proxy'
 import type {
   DefaultError,
   InfiniteData,
+  InfiniteQueryObserverResult,
   QueryKey,
   QueryObserver,
 } from '@tanstack/query-core'
@@ -110,8 +112,20 @@ export function injectInfiniteQuery<
  * @param options - Additional configuration.
  * @returns The infinite query result.
  */
-export function injectInfiniteQuery(
-  injectInfiniteQueryFn: () => CreateInfiniteQueryOptions,
+export function injectInfiniteQuery<
+  TQueryFnData,
+  TError = DefaultError,
+  TData = InfiniteData<TQueryFnData>,
+  TQueryKey extends QueryKey = QueryKey,
+  TPageParam = unknown,
+>(
+  injectInfiniteQueryFn: () => CreateInfiniteQueryOptions<
+    TQueryFnData,
+    TError,
+    TData,
+    TQueryKey,
+    TPageParam
+  >,
   options?: InjectInfiniteQueryOptions,
 ) {
   !options?.injector && assertInInjectionContext(injectInfiniteQuery)
@@ -120,6 +134,13 @@ export function injectInfiniteQuery(
     createBaseQuery(
       injectInfiniteQueryFn,
       InfiniteQueryObserver as typeof QueryObserver,
+      methodsToExclude,
     ),
   )
 }
+
+const methodsToExclude: Array<MethodKeys<InfiniteQueryObserverResult>> = [
+  'fetchNextPage',
+  'fetchPreviousPage',
+  'refetch',
+]
diff --git a/packages/angular-query-experimental/src/inject-mutation.ts b/packages/angular-query-experimental/src/inject-mutation.ts
index 7eb605047f..3399d5f332 100644
--- a/packages/angular-query-experimental/src/inject-mutation.ts
+++ b/packages/angular-query-experimental/src/inject-mutation.ts
@@ -1,6 +1,7 @@
 import {
   Injector,
   NgZone,
+  PendingTasks,
   assertInInjectionContext,
   computed,
   effect,
@@ -16,8 +17,6 @@ import {
   shouldThrowError,
 } from '@tanstack/query-core'
 import { signalProxy } from './signal-proxy'
-import { PENDING_TASKS } from './pending-tasks-compat'
-import type { PendingTaskRef } from './pending-tasks-compat'
 import type { DefaultError, MutationObserverResult } from '@tanstack/query-core'
 import type {
   CreateMutateFunction,
@@ -59,7 +58,7 @@ export function injectMutation<
   !options?.injector && assertInInjectionContext(injectMutation)
   const injector = options?.injector ?? inject(Injector)
   const ngZone = injector.get(NgZone)
-  const pendingTasks = injector.get(PENDING_TASKS)
+  const pendingTasks = injector.get(PendingTasks)
   const queryClient = injector.get(QueryClient)
 
   /**
@@ -69,18 +68,23 @@ export function injectMutation<
    */
   const optionsSignal = computed(injectMutationFn)
 
-  const observerSignal = (() => {
-    let instance: MutationObserver<
-      TData,
-      TError,
-      TVariables,
-      TOnMutateResult
-    > | null = null
+  const observerSignal = computed(() => new MutationObserver(queryClient, untracked(optionsSignal)))
 
-    return computed(() => {
-      return (instance ||= new MutationObserver(queryClient, optionsSignal()))
-    })
-  })()
+  let destroyed = false
+  let taskCleanupRef: (() => void) | null = null
+
+  const startPendingTask = () => {
+    if (!taskCleanupRef && !destroyed) {
+      taskCleanupRef = pendingTasks.add()
+    }
+  }
+
+  const stopPendingTask = () => {
+    if (taskCleanupRef) {
+      taskCleanupRef()
+      taskCleanupRef = null
+    }
+  }
 
   const mutateFnSignal = computed<
     CreateMutateFunction<TData, TError, TVariables, TOnMutateResult>
@@ -125,24 +129,19 @@ export function injectMutation<
 
   effect(
     (onCleanup) => {
-      // observer.trackResult is not used as this optimization is not needed for Angular
       const observer = observerSignal()
-      let pendingTaskRef: PendingTaskRef | null = null
 
       untracked(() => {
         const unsubscribe = ngZone.runOutsideAngular(() =>
           observer.subscribe(
             notifyManager.batchCalls((state) => {
               ngZone.run(() => {
-                // Track pending task when mutation is pending
-                if (state.isPending && !pendingTaskRef) {
-                  pendingTaskRef = pendingTasks.add()
-                }
+                if (destroyed) return
 
-                // Clear pending task when mutation is no longer pending
-                if (!state.isPending && pendingTaskRef) {
-                  pendingTaskRef()
-                  pendingTaskRef = null
+                if (state.isPending) {
+                  startPendingTask()
+                } else {
+                  stopPendingTask()
                 }
 
                 if (
@@ -159,11 +158,8 @@ export function injectMutation<
           ),
         )
         onCleanup(() => {
-          // Clean up any pending task on destroy
-          if (pendingTaskRef) {
-            pendingTaskRef()
-            pendingTaskRef = null
-          }
+          destroyed = true
+          stopPendingTask()
           unsubscribe()
         })
       })
@@ -186,10 +182,9 @@ export function injectMutation<
     }
   })
 
-  return signalProxy(resultSignal) as CreateMutationResult<
-    TData,
-    TError,
-    TVariables,
-    TOnMutateResult
-  >
+  return signalProxy(resultSignal, [
+    'mutate',
+    'mutateAsync',
+    'reset',
+  ]) as CreateMutationResult<TData, TError, TVariables, TOnMutateResult>
 }
diff --git a/packages/angular-query-experimental/src/inject-queries.ts b/packages/angular-query-experimental/src/inject-queries.ts
index 2f201799e7..eb9a7af7f2 100644
--- a/packages/angular-query-experimental/src/inject-queries.ts
+++ b/packages/angular-query-experimental/src/inject-queries.ts
@@ -7,24 +7,27 @@ import {
   DestroyRef,
   Injector,
   NgZone,
+  PendingTasks,
   assertInInjectionContext,
   computed,
   effect,
   inject,
+  linkedSignal,
   runInInjectionContext,
-  signal,
   untracked,
 } from '@angular/core'
 import { signalProxy } from './signal-proxy'
 import { injectIsRestoring } from './inject-is-restoring'
 import type {
   DefaultError,
+  DefinedQueryObserverResult,
   OmitKeyof,
   QueriesObserverOptions,
   QueriesPlaceholderDataFunction,
   QueryFunction,
   QueryKey,
   QueryObserverOptions,
+  QueryObserverResult,
   ThrowOnError,
 } from '@tanstack/query-core'
 import type {
@@ -33,6 +36,7 @@ import type {
   DefinedCreateQueryResult,
 } from './types'
 import type { Signal } from '@angular/core'
+import type { MethodKeys } from './signal-proxy'
 
 // This defines the `CreateQueryOptions` that are accepted in `QueriesOptions` & `GetOptions`.
 // `placeholderData` function always gets undefined passed
@@ -90,39 +94,42 @@ type GetCreateQueryOptionsForCreateQueries<T> =
                 : // Fallback
                   QueryObserverOptionsForCreateQueries
 
-// A defined initialData setting should return a DefinedCreateQueryResult rather than CreateQueryResult
-type GetDefinedOrUndefinedQueryResult<T, TData, TError = unknown> = T extends {
-  initialData?: infer TInitialData
-}
-  ? unknown extends TInitialData
-    ? CreateQueryResult<TData, TError>
-    : TInitialData extends TData
-      ? DefinedCreateQueryResult<TData, TError>
-      : TInitialData extends () => infer TInitialDataResult
-        ? unknown extends TInitialDataResult
-          ? CreateQueryResult<TData, TError>
-          : TInitialDataResult extends TData
-            ? DefinedCreateQueryResult<TData, TError>
-            : CreateQueryResult<TData, TError>
-        : CreateQueryResult<TData, TError>
-  : CreateQueryResult<TData, TError>
-
-type GetCreateQueryResult<T> =
-  // Part 1: responsible for mapping explicit type parameter to function result, if object
+// Generic wrapper that handles initialData logic for any result type pair
+type GenericGetDefinedOrUndefinedQueryResult<T, TData, TUndefined, TDefined> =
+  T extends {
+    initialData?: infer TInitialData
+  }
+    ? unknown extends TInitialData
+      ? TUndefined
+      : TInitialData extends TData
+        ? TDefined
+        : TInitialData extends () => infer TInitialDataResult
+          ? unknown extends TInitialDataResult
+            ? TUndefined
+            : TInitialDataResult extends TData
+              ? TDefined
+              : TUndefined
+          : TUndefined
+    : TUndefined
+
+// Infer TData and TError from query options
+// Shared type between the results with and without the combine function
+type InferDataAndError<T> =
+  // Part 1: explicit type parameter as object { queryFnData, error, data }
   T extends { queryFnData: any; error?: infer TError; data: infer TData }
-    ? GetDefinedOrUndefinedQueryResult<T, TData, TError>
+    ? { data: TData; error: TError }
     : T extends { queryFnData: infer TQueryFnData; error?: infer TError }
-      ? GetDefinedOrUndefinedQueryResult<T, TQueryFnData, TError>
+      ? { data: TQueryFnData; error: TError }
       : T extends { data: infer TData; error?: infer TError }
-        ? GetDefinedOrUndefinedQueryResult<T, TData, TError>
-        : // Part 2: responsible for mapping explicit type parameter to function result, if tuple
+        ? { data: TData; error: TError }
+        : // Part 2: explicit type parameter as tuple [TQueryFnData, TError, TData]
           T extends [any, infer TError, infer TData]
-          ? GetDefinedOrUndefinedQueryResult<T, TData, TError>
+          ? { data: TData; error: TError }
           : T extends [infer TQueryFnData, infer TError]
-            ? GetDefinedOrUndefinedQueryResult<T, TQueryFnData, TError>
+            ? { data: TQueryFnData; error: TError }
             : T extends [infer TQueryFnData]
-              ? GetDefinedOrUndefinedQueryResult<T, TQueryFnData>
-              : // Part 3: responsible for mapping inferred type to results, if no explicit parameter was provided
+              ? { data: TQueryFnData; error: unknown }
+              : // Part 3: infer from queryFn, select, throwOnError
                 T extends {
                     queryFn?:
                       | QueryFunction<infer TQueryFnData, any>
@@ -130,13 +137,40 @@ type GetCreateQueryResult<T> =
                     select?: (data: any) => infer TData
                     throwOnError?: ThrowOnError<any, infer TError, any, any>
                   }
-                ? GetDefinedOrUndefinedQueryResult<
-                    T,
-                    unknown extends TData ? TQueryFnData : TData,
-                    unknown extends TError ? DefaultError : TError
-                  >
+                ? {
+                    data: unknown extends TData ? TQueryFnData : TData
+                    error: unknown extends TError ? DefaultError : TError
+                  }
                 : // Fallback
-                  CreateQueryResult
+                  { data: unknown; error: DefaultError }
+
+// Maps query options to Angular's signal-wrapped CreateQueryResult
+type GetCreateQueryResult<T> = GenericGetDefinedOrUndefinedQueryResult<
+  T,
+  InferDataAndError<T>['data'],
+  CreateQueryResult<
+    InferDataAndError<T>['data'],
+    InferDataAndError<T>['error']
+  >,
+  DefinedCreateQueryResult<
+    InferDataAndError<T>['data'],
+    InferDataAndError<T>['error']
+  >
+>
+
+// Maps query options to plain QueryObserverResult for combine function
+type GetQueryObserverResult<T> = GenericGetDefinedOrUndefinedQueryResult<
+  T,
+  InferDataAndError<T>['data'],
+  QueryObserverResult<
+    InferDataAndError<T>['data'],
+    InferDataAndError<T>['error']
+  >,
+  DefinedQueryObserverResult<
+    InferDataAndError<T>['data'],
+    InferDataAndError<T>['error']
+  >
+>
 
 /**
  * QueriesOptions reducer recursively unwraps function arguments to infer/enforce type param
@@ -201,6 +235,25 @@ export type QueriesResults<
           >
         : { [K in keyof T]: GetCreateQueryResult<T[K]> }
 
+// Maps query options array to plain QueryObserverResult types for combine function
+type RawQueriesResults<
+  T extends Array<any>,
+  TResults extends Array<any> = [],
+  TDepth extends ReadonlyArray<number> = [],
+> = TDepth['length'] extends MAXIMUM_DEPTH
+  ? Array<QueryObserverResult>
+  : T extends []
+    ? []
+    : T extends [infer Head]
+      ? [...TResults, GetQueryObserverResult<Head>]
+      : T extends [infer Head, ...infer Tails]
+        ? RawQueriesResults<
+            [...Tails],
+            [...TResults, GetQueryObserverResult<Head>],
+            [...TDepth, 1]
+          >
+        : { [K in keyof T]: GetQueryObserverResult<T[K]> }
+
 export interface InjectQueriesOptions<
   T extends Array<any>,
   TCombinedResult = QueriesResults<T>,
@@ -210,9 +263,14 @@ export interface InjectQueriesOptions<
     | readonly [
         ...{ [K in keyof T]: GetCreateQueryOptionsForCreateQueries<T[K]> },
       ]
-  combine?: (result: QueriesResults<T>) => TCombinedResult
+  combine?: (result: RawQueriesResults<T>) => TCombinedResult
 }
 
+const methodsToExclude: Array<MethodKeys<QueryObserverResult>> = ['refetch']
+
+const hasPendingQueriesState = (results: Array<QueryObserverResult>): boolean =>
+  results.some((result) => result.fetchStatus !== 'idle')
+
 /**
  * @param optionsFn - A function that returns queries' options.
  * @param injector - The Angular injector to use.
@@ -228,8 +286,24 @@ export function injectQueries<
   return runInInjectionContext(injector ?? inject(Injector), () => {
     const destroyRef = inject(DestroyRef)
     const ngZone = inject(NgZone)
+    const pendingTasks = inject(PendingTasks)
     const queryClient = inject(QueryClient)
     const isRestoring = injectIsRestoring()
+    let destroyed = false
+    let taskCleanupRef: (() => void) | null = null
+
+    const startPendingTask = () => {
+      if (!taskCleanupRef && !destroyed) {
+        taskCleanupRef = pendingTasks.add()
+      }
+    }
+
+    const stopPendingTask = () => {
+      if (taskCleanupRef) {
+        taskCleanupRef()
+        taskCleanupRef = null
+      }
+    }
 
     /**
      * Signal that has the default options from query client applied
@@ -255,76 +329,125 @@ export function injectQueries<
       })
     })
 
-    const observerSignal = (() => {
-      let instance: QueriesObserver<TCombinedResult> | null = null
+    const observerOptionsSignal = computed(
+      () => optionsSignal() as QueriesObserverOptions<TCombinedResult>,
+    )
 
-      return computed(() => {
-        return (instance ||= new QueriesObserver<TCombinedResult>(
-          queryClient,
-          defaultedQueries(),
-          optionsSignal() as QueriesObserverOptions<TCombinedResult>,
-        ))
-      })
-    })()
+    // Computed without deps to lazy initialize the observer
+    const observerSignal = computed(() => {
+      return new QueriesObserver<TCombinedResult>(
+        queryClient,
+        untracked(defaultedQueries),
+        untracked(observerOptionsSignal),
+      )
+    })
 
     const optimisticResultSignal = computed(() =>
       observerSignal().getOptimisticResult(
         defaultedQueries(),
-        (optionsSignal() as QueriesObserverOptions<TCombinedResult>).combine,
+        observerOptionsSignal().combine,
       ),
     )
 
     // Do not notify on updates because of changes in the options because
     // these changes should already be reflected in the optimistic result.
     effect(() => {
-      observerSignal().setQueries(
-        defaultedQueries(),
-        optionsSignal() as QueriesObserverOptions<TCombinedResult>,
-      )
+      observerSignal().setQueries(defaultedQueries(), observerOptionsSignal())
     })
 
-    const optimisticCombinedResultSignal = computed(() => {
-      const [_optimisticResult, getCombinedResult, trackResult] =
-        optimisticResultSignal()
-      return getCombinedResult(trackResult())
+    const optimisticResultSourceSignal = computed(() => {
+      const options = observerOptionsSignal()
+      return { queries: defaultedQueries(), combine: options.combine }
     })
 
-    const resultFromSubscriberSignal = signal<TCombinedResult | null>(null)
+    const resultSignal = linkedSignal({
+      source: optimisticResultSourceSignal,
+      computation: () => {
+        const observer = untracked(observerSignal)
+        const [_optimisticResult, getCombinedResult, trackResult] =
+          observer.getOptimisticResult(
+            defaultedQueries(),
+            observerOptionsSignal().combine,
+          )
+        return getCombinedResult(trackResult())
+      },
+    })
 
-    effect(() => {
+    effect((onCleanup) => {
       const observer = observerSignal()
-      const [_optimisticResult, getCombinedResult] = optimisticResultSignal()
-
-      untracked(() => {
-        const unsubscribe = isRestoring()
-          ? () => undefined
-          : ngZone.runOutsideAngular(() =>
-              observer.subscribe(
-                notifyManager.batchCalls((state) => {
-                  resultFromSubscriberSignal.set(getCombinedResult(state))
-                }),
-              ),
-            )
-
-        destroyRef.onDestroy(unsubscribe)
+      const [optimisticResult, getCombinedResult] = optimisticResultSignal()
+
+      if (isRestoring()) {
+        stopPendingTask()
+        return
+      }
+
+      if (hasPendingQueriesState(optimisticResult)) {
+        startPendingTask()
+      } else {
+        stopPendingTask()
+      }
+
+      const unsubscribe = untracked(() =>
+        ngZone.runOutsideAngular(() =>
+          observer.subscribe((state) => {
+            if (hasPendingQueriesState(state)) {
+              startPendingTask()
+            } else {
+              stopPendingTask()
+            }
+
+            queueMicrotask(() => {
+              if (destroyed) return
+              notifyManager.batch(() => {
+                ngZone.run(() => {
+                  resultSignal.set(getCombinedResult(state))
+                })
+              })
+            })
+          }),
+        ),
+      )
+
+      onCleanup(() => {
+        unsubscribe()
+        stopPendingTask()
       })
     })
 
-    const resultSignal = computed(() => {
-      const subscriberResult = resultFromSubscriberSignal()
-      const optimisticResult = optimisticCombinedResultSignal()
-      return subscriberResult ?? optimisticResult
+    // Angular does not use reactive getters on plain objects, so we wrap each
+    // QueryObserverResult in a signal-backed proxy to keep field-level tracking
+    // (`result.data()`, `result.status()`, etc.).
+    // Solid uses a related proxy approach in useQueries, but there it proxies
+    // object fields for store/resource reactivity rather than callable signals.
+    const createResultProxy = (index: number) =>
+      signalProxy(
+        computed(() => (resultSignal() as Array<QueryObserverResult>)[index]!),
+        methodsToExclude,
+      )
+
+    // Keep this positional to match QueriesObserver semantics.
+    // Like Solid/Vue adapters, proxies are rebuilt from current observer output.
+    const proxiedResultsSignal = computed(() =>
+      (resultSignal() as Array<QueryObserverResult>).map((_, index) =>
+        createResultProxy(index),
+      ),
+    )
+
+    destroyRef.onDestroy(() => {
+      destroyed = true
+      stopPendingTask()
     })
 
     return computed(() => {
       const result = resultSignal()
       const { combine } = optionsSignal()
 
-      return combine
-        ? result
-        : (result as QueriesResults<T>).map((query) =>
-            signalProxy(signal(query)),
-          )
+      if (combine) {
+        return result
+      }
+
+      return proxiedResultsSignal() as unknown as TCombinedResult
     })
   }) as unknown as Signal<TCombinedResult>
 }
diff --git a/packages/angular-query-experimental/src/inject-query.ts b/packages/angular-query-experimental/src/inject-query.ts
index 1dac0ab694..2161fb225a 100644
--- a/packages/angular-query-experimental/src/inject-query.ts
+++ b/packages/angular-query-experimental/src/inject-query.ts
@@ -6,7 +6,12 @@ import {
   runInInjectionContext,
 } from '@angular/core'
 import { createBaseQuery } from './create-base-query'
-import type { DefaultError, QueryKey } from '@tanstack/query-core'
+import type { MethodKeys } from './signal-proxy'
+import type {
+  DefaultError,
+  QueryKey,
+  QueryObserverResult,
+} from '@tanstack/query-core'
 import type {
   CreateQueryOptions,
   CreateQueryResult,
@@ -31,11 +36,15 @@ export interface InjectQueryOptions {
  *
  * **Basic example**
  * ```ts
+ * import { lastValueFrom } from 'rxjs'
+ *
  * class ServiceOrComponent {
  *   query = injectQuery(() => ({
  *     queryKey: ['repoData'],
  *     queryFn: () =>
- *       this.#http.get<Response>('https://api.github.com/repos/tanstack/query'),
+ *       lastValueFrom(
+ *         this.#http.get<Response>('https://api.github.com/repos/tanstack/query'),
+ *       ),
  *   }))
  * }
  * ```
@@ -82,11 +91,15 @@ export function injectQuery<
  *
  * **Basic example**
  * ```ts
+ * import { lastValueFrom } from 'rxjs'
+ *
  * class ServiceOrComponent {
  *   query = injectQuery(() => ({
  *     queryKey: ['repoData'],
  *     queryFn: () =>
- *       this.#http.get<Response>('https://api.github.com/repos/tanstack/query'),
+ *       lastValueFrom(
+ *         this.#http.get<Response>('https://api.github.com/repos/tanstack/query'),
+ *       ),
  *   }))
  * }
  * ```
@@ -133,11 +146,15 @@ export function injectQuery<
  *
  * **Basic example**
  * ```ts
+ * import { lastValueFrom } from 'rxjs'
+ *
  * class ServiceOrComponent {
  *   query = injectQuery(() => ({
  *     queryKey: ['repoData'],
  *     queryFn: () =>
- *       this.#http.get<Response>('https://api.github.com/repos/tanstack/query'),
+ *       lastValueFrom(
+ *         this.#http.get<Response>('https://api.github.com/repos/tanstack/query'),
+ *       ),
  *   }))
  * }
  * ```
@@ -184,11 +201,15 @@ export function injectQuery<
  *
  * **Basic example**
  * ```ts
+ * import { lastValueFrom } from 'rxjs'
+ *
  * class ServiceOrComponent {
  *   query = injectQuery(() => ({
  *     queryKey: ['repoData'],
  *     queryFn: () =>
- *       this.#http.get<Response>('https://api.github.com/repos/tanstack/query'),
+ *       lastValueFrom(
+ *         this.#http.get<Response>('https://api.github.com/repos/tanstack/query'),
+ *       ),
  *   }))
  * }
  * ```
@@ -221,6 +242,8 @@ export function injectQuery(
 ) {
   !options?.injector && assertInInjectionContext(injectQuery)
   return runInInjectionContext(options?.injector ?? inject(Injector), () =>
-    createBaseQuery(injectQueryFn, QueryObserver),
+    createBaseQuery(injectQueryFn, QueryObserver, methodsToExclude),
   ) as unknown as CreateQueryResult
 }
+
+const methodsToExclude: Array<MethodKeys<QueryObserverResult>> = ['refetch']
diff --git a/packages/angular-query-experimental/src/pending-tasks-compat.ts b/packages/angular-query-experimental/src/pending-tasks-compat.ts
deleted file mode 100644
index e156996993..0000000000
--- a/packages/angular-query-experimental/src/pending-tasks-compat.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-import { InjectionToken, inject } from '@angular/core'
-import * as ng from '@angular/core'
-import { noop } from '@tanstack/query-core'
-
-type PendingTasksCompat = { add: () => PendingTaskRef }
-
-export type PendingTaskRef = () => void
-
-export const PENDING_TASKS = new InjectionToken<PendingTasksCompat>(
-  'PENDING_TASKS',
-  {
-    factory: (): PendingTasksCompat => {
-      // Access via Reflect so bundlers stay quiet when the token is absent (Angular < 19).
-      const token = Reflect.get(ng, 'PendingTasks') as unknown as
-        | Parameters<typeof inject>[0]
-        | undefined
-
-      const svc: PendingTasksCompat | null = token
-        ? (inject(token, { optional: true }) as PendingTasksCompat | null)
-        : null
-
-      // Without PendingTasks we fall back to a stable no-op shim.
-      return {
-        add: svc ? () => svc.add() : () => noop,
-      }
-    },
-  },
-)
diff --git a/packages/angular-query-experimental/src/query-options.ts b/packages/angular-query-experimental/src/query-options.ts
index 069472b903..780e14ce1b 100644
--- a/packages/angular-query-experimental/src/query-options.ts
+++ b/packages/angular-query-experimental/src/query-options.ts
@@ -4,7 +4,6 @@ import type {
   InitialDataFunction,
   NonUndefinedGuard,
   OmitKeyof,
-  QueryFunction,
   QueryKey,
   SkipToken,
 } from '@tanstack/query-core'
@@ -42,14 +41,10 @@ export type DefinedInitialDataOptions<
   TError = DefaultError,
   TData = TQueryFnData,
   TQueryKey extends QueryKey = QueryKey,
-> = Omit<
-  CreateQueryOptions<TQueryFnData, TError, TData, TQueryKey>,
-  'queryFn'
-> & {
+> = CreateQueryOptions<TQueryFnData, TError, TData, TQueryKey> & {
   initialData:
     | NonUndefinedGuard<TQueryFnData>
     | (() => NonUndefinedGuard<TQueryFnData>)
-  queryFn?: QueryFunction<TQueryFnData, TQueryKey>
 }
 
 /**
diff --git a/packages/angular-query-experimental/src/signal-proxy.ts b/packages/angular-query-experimental/src/signal-proxy.ts
index e2a9de345f..fa857dcda2 100644
--- a/packages/angular-query-experimental/src/signal-proxy.ts
+++ b/packages/angular-query-experimental/src/signal-proxy.ts
@@ -1,46 +1,61 @@
 import { computed, untracked } from '@angular/core'
 import type { Signal } from '@angular/core'
 
-export type MapToSignals<T> = {
-  [K in keyof T]: T[K] extends Function ? T[K] : Signal<T[K]>
+export type MethodKeys<T> = {
+  [K in keyof T]: T[K] extends (...args: Array<any>) => any ? K : never
+}[keyof T]
+
+export type MapToSignals<T, TExcludeFields extends MethodKeys<T> = never> = {
+  [K in keyof T]: K extends TExcludeFields ? T[K] : Signal<T[K]>
 }
 
 /**
  * Exposes fields of an object passed via an Angular `Signal` as `Computed` signals.
  * Functions on the object are passed through as-is.
  * @param inputSignal - `Signal` that must return an object.
+ * @param excludeFields - Array of function property names that should NOT be converted to signals.
  * @returns A proxy object with the same fields as the input object, but with each field wrapped in a `Computed` signal.
  */
-export function signalProxy<TInput extends Record<string | symbol, any>>(
-  inputSignal: Signal<TInput>,
-) {
-  const internalState = {} as MapToSignals<TInput>
+export function signalProxy<
+  TInput extends Record<string | symbol, any>,
+  const TExcludeFields extends ReadonlyArray<MethodKeys<TInput>> = [],
+>(inputSignal: Signal<TInput>, excludeFields: TExcludeFields) {
+  const internalState = {} as MapToSignals<TInput, TExcludeFields[number]>
+  const excludeFieldsArray = excludeFields as ReadonlyArray<string>
 
-  return new Proxy<MapToSignals<TInput>>(internalState, {
-    get(target, prop) {
-      // first check if we have it in our internal state and return it
-      const computedField = target[prop]
-      if (computedField) return computedField
+  return new Proxy<MapToSignals<TInput, TExcludeFields[number]>>(
+    internalState,
+    {
+      get(target, prop) {
+        // first check if we have it in our internal state and return it
+        const computedField = target[prop]
+        if (computedField) return computedField
 
-      // then, check if it's a function on the resultState and return it
-      const targetField = untracked(inputSignal)[prop]
-      if (typeof targetField === 'function') return targetField
+        // if it is an excluded function, return it without tracking
+        if (excludeFieldsArray.includes(prop as string)) {
+          const fn = (...args: Parameters<TInput[typeof prop]>) =>
+            untracked(inputSignal)[prop](...args)
+          // @ts-expect-error
+          target[prop] = fn
+          return fn
+        }
 
-      // finally, create a computed field, store it and return it
-      // @ts-expect-error
-      return (target[prop] = computed(() => inputSignal()[prop]))
-    },
-    has(_, prop) {
-      return !!untracked(inputSignal)[prop]
-    },
-    ownKeys() {
-      return Reflect.ownKeys(untracked(inputSignal))
-    },
-    getOwnPropertyDescriptor() {
-      return {
-        enumerable: true,
-        configurable: true,
-      }
+        // otherwise, make a computed field
+        // @ts-expect-error
+        return (target[prop] = computed(() => inputSignal()[prop]))
+      },
+      has(_, prop) {
+        return !!untracked(inputSignal)[prop]
+      },
+      ownKeys() {
+        return Reflect.ownKeys(untracked(inputSignal))
+      },
+      getOwnPropertyDescriptor() {
+        return {
+          enumerable: true,
+          configurable: true,
+        }
+      },
     },
-  })
+  )
 }
diff --git a/packages/angular-query-experimental/src/types.ts b/packages/angular-query-experimental/src/types.ts
index d71bec248f..5c36a6bb27 100644
--- a/packages/angular-query-experimental/src/types.ts
+++ b/packages/angular-query-experimental/src/types.ts
@@ -16,31 +16,25 @@ import type {
   QueryObserverResult,
 } from '@tanstack/query-core'
 import type { Signal } from '@angular/core'
-import type { MapToSignals } from './signal-proxy'
+import type { MapToSignals, MethodKeys } from './signal-proxy'
 
-export interface CreateBaseQueryOptions<
+export type CreateBaseQueryOptions<
   TQueryFnData = unknown,
   TError = DefaultError,
   TData = TQueryFnData,
   TQueryData = TQueryFnData,
   TQueryKey extends QueryKey = QueryKey,
-> extends QueryObserverOptions<
-  TQueryFnData,
-  TError,
-  TData,
-  TQueryData,
-  TQueryKey
-> {}
+> = QueryObserverOptions<TQueryFnData, TError, TData, TQueryData, TQueryKey>
 
-export interface CreateQueryOptions<
+export type CreateQueryOptions<
   TQueryFnData = unknown,
   TError = DefaultError,
   TData = TQueryFnData,
   TQueryKey extends QueryKey = QueryKey,
-> extends OmitKeyof<
+> = OmitKeyof<
   CreateBaseQueryOptions<TQueryFnData, TError, TData, TQueryFnData, TQueryKey>,
   'suspense'
-> {}
+>
 
 type CreateStatusBasedQueryResult<
   TStatus extends QueryObserverResult['status'],
@@ -94,7 +88,10 @@ export type CreateBaseQueryResult<
   TError = DefaultError,
   TState = QueryObserverResult<TData, TError>,
 > = BaseQueryNarrowing<TData, TError> &
-  MapToSignals<OmitKeyof<TState, keyof BaseQueryNarrowing, 'safely'>>
+  MapToSignals<
+    OmitKeyof<TState, keyof BaseQueryNarrowing, 'safely'>,
+    MethodKeys<OmitKeyof<TState, keyof BaseQueryNarrowing, 'safely'>>
+  >
 
 export type CreateQueryResult<
   TData = unknown,
@@ -106,13 +103,19 @@ export type DefinedCreateQueryResult<
   TError = DefaultError,
   TState = DefinedQueryObserverResult<TData, TError>,
 > = BaseQueryNarrowing<TData, TError> &
-  MapToSignals<OmitKeyof<TState, keyof BaseQueryNarrowing, 'safely'>>
+  MapToSignals<
+    OmitKeyof<TState, keyof BaseQueryNarrowing, 'safely'>,
+    MethodKeys<OmitKeyof<TState, keyof BaseQueryNarrowing, 'safely'>>
+  >
 
 export type CreateInfiniteQueryResult<
   TData = unknown,
   TError = DefaultError,
 > = BaseQueryNarrowing<TData, TError> &
-  MapToSignals<InfiniteQueryObserverResult<TData, TError>>
+  MapToSignals<
+    InfiniteQueryObserverResult<TData, TError>,
+    MethodKeys<InfiniteQueryObserverResult<TData, TError>>
+  >
 
 export type DefinedCreateInfiniteQueryResult<
   TData = unknown,
@@ -121,7 +124,10 @@ export type DefinedCreateInfiniteQueryResult<
     TData,
     TError
   >,
-> = MapToSignals<TDefinedInfiniteQueryObserver>
+> = MapToSignals<
+  TDefinedInfiniteQueryObserver,
+  MethodKeys<TDefinedInfiniteQueryObserver>
+>
 
 export interface CreateMutationOptions<
   TData = unknown,
@@ -270,4 +276,7 @@ export type CreateMutationResult<
     TOnMutateResult
   >,
 > = BaseMutationNarrowing<TData, TError, TVariables, TOnMutateResult> &
-  MapToSignals<OmitKeyof<TState, keyof BaseMutationNarrowing, 'safely'>>
+  MapToSignals<
+    OmitKeyof<TState, keyof BaseMutationNarrowing, 'safely'>,
+    MethodKeys<OmitKeyof<TState, keyof BaseMutationNarrowing, 'safely'>>
+  >
diff --git a/packages/angular-query-persist-client/package.json b/packages/angular-query-persist-client/package.json
index 4ed0e7cc2b..083696df49 100644
--- a/packages/angular-query-persist-client/package.json
+++ b/packages/angular-query-persist-client/package.json
@@ -20,11 +20,6 @@
     "compile": "tsc --build",
     "test:eslint": "eslint --concurrency=auto ./src",
     "test:types": "npm-run-all --serial test:types:*",
-    "test:types:ts50": "node ../../node_modules/typescript50/lib/tsc.js --build",
-    "test:types:ts51": "node ../../node_modules/typescript51/lib/tsc.js --build",
-    "test:types:ts52": "node ../../node_modules/typescript52/lib/tsc.js --build",
-    "test:types:ts53": "node ../../node_modules/typescript53/lib/tsc.js --build",
-    "test:types:ts54": "node ../../node_modules/typescript54/lib/tsc.js --build",
     "test:types:ts55": "node ../../node_modules/typescript55/lib/tsc.js --build",
     "test:types:ts56": "node ../../node_modules/typescript56/lib/tsc.js --build",
     "test:types:ts57": "node ../../node_modules/typescript57/lib/tsc.js --build",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 1af1216e90..37ffa0372a 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -174,7 +174,7 @@ importers:
     devDependencies:
       '@angular/build':
         specifier: ^20.0.0
-        version: 20.0.0(8379d9408f101aa649c5ec9eae189324)
+        version: 20.0.0(e7d71ef5d6f07f95ae57395d944dd75a)
       '@angular/cli':
         specifier: ^20.0.0
         version: 20.0.0(@types/node@22.15.3)(chokidar@4.0.3)
@@ -214,7 +214,7 @@ importers:
     devDependencies:
       '@angular/build':
         specifier: ^20.0.0
-        version: 20.0.0(8379d9408f101aa649c5ec9eae189324)
+        version: 20.0.0(e7d71ef5d6f07f95ae57395d944dd75a)
       '@angular/cli':
         specifier: ^20.0.0
         version: 20.0.0(@types/node@22.15.3)(chokidar@4.0.3)
@@ -260,7 +260,7 @@ importers:
     devDependencies:
       '@angular/build':
         specifier: ^20.0.0
-        version: 20.0.0(8379d9408f101aa649c5ec9eae189324)
+        version: 20.0.0(e7d71ef5d6f07f95ae57395d944dd75a)
       '@angular/cli':
         specifier: ^20.0.0
         version: 20.0.0(@types/node@22.15.3)(chokidar@4.0.3)
@@ -303,7 +303,7 @@ importers:
     devDependencies:
       '@angular/build':
         specifier: ^20.0.0
-        version: 20.0.0(8379d9408f101aa649c5ec9eae189324)
+        version: 20.0.0(e7d71ef5d6f07f95ae57395d944dd75a)
       '@angular/cli':
         specifier: ^20.0.0
         version: 20.0.0(@types/node@22.15.3)(chokidar@4.0.3)
@@ -343,7 +343,7 @@ importers:
     devDependencies:
       '@angular/build':
         specifier: ^20.0.0
-        version: 20.0.0(8379d9408f101aa649c5ec9eae189324)
+        version: 20.0.0(e7d71ef5d6f07f95ae57395d944dd75a)
       '@angular/cli':
         specifier: ^20.0.0
         version: 20.0.0(@types/node@22.15.3)(chokidar@4.0.3)
@@ -386,7 +386,7 @@ importers:
     devDependencies:
       '@angular/build':
         specifier: ^20.0.0
-        version: 20.0.0(8379d9408f101aa649c5ec9eae189324)
+        version: 20.0.0(e7d71ef5d6f07f95ae57395d944dd75a)
       '@angular/cli':
         specifier: ^20.0.0
         version: 20.0.0(@types/node@22.15.3)(chokidar@4.0.3)
@@ -426,7 +426,7 @@ importers:
     devDependencies:
       '@angular/build':
         specifier: ^20.0.0
-        version: 20.0.0(8379d9408f101aa649c5ec9eae189324)
+        version: 20.0.0(e7d71ef5d6f07f95ae57395d944dd75a)
       '@angular/cli':
         specifier: ^20.0.0
         version: 20.0.0(@types/node@22.15.3)(chokidar@4.0.3)
@@ -469,7 +469,7 @@ importers:
     devDependencies:
       '@angular/build':
         specifier: ^20.0.0
-        version: 20.0.0(8379d9408f101aa649c5ec9eae189324)
+        version: 20.0.0(e7d71ef5d6f07f95ae57395d944dd75a)
       '@angular/cli':
         specifier: ^20.0.0
         version: 20.0.0(@types/node@22.15.3)(chokidar@4.0.3)
@@ -512,7 +512,7 @@ importers:
     devDependencies:
       '@angular/build':
         specifier: ^20.0.0
-        version: 20.0.0(8379d9408f101aa649c5ec9eae189324)
+        version: 20.0.0(e7d71ef5d6f07f95ae57395d944dd75a)
       '@angular/cli':
         specifier: ^20.0.0
         version: 20.0.0(@types/node@22.15.3)(chokidar@4.0.3)
@@ -555,7 +555,7 @@ importers:
     devDependencies:
       '@angular/build':
         specifier: ^20.0.0
-        version: 20.0.0(8379d9408f101aa649c5ec9eae189324)
+        version: 20.0.0(e7d71ef5d6f07f95ae57395d944dd75a)
       '@angular/cli':
         specifier: ^20.0.0
         version: 20.0.0(@types/node@22.15.3)(chokidar@4.0.3)
@@ -595,7 +595,7 @@ importers:
     devDependencies:
       '@angular/build':
         specifier: ^20.0.0
-        version: 20.0.0(8379d9408f101aa649c5ec9eae189324)
+        version: 20.0.0(e7d71ef5d6f07f95ae57395d944dd75a)
       '@angular/cli':
         specifier: ^20.0.0
         version: 20.0.0(@types/node@22.15.3)(chokidar@4.0.3)
@@ -2000,7 +2000,7 @@ importers:
     devDependencies:
       '@angular/build':
         specifier: ^20.0.0
-        version: 20.0.0(8379d9408f101aa649c5ec9eae189324)
+        version: 20.0.0(e7d71ef5d6f07f95ae57395d944dd75a)
       '@angular/cli':
         specifier: ^20.0.0
         version: 20.0.0(@types/node@22.15.3)(chokidar@4.0.3)
@@ -2262,22 +2262,25 @@ importers:
     devDependencies:
       '@angular/common':
         specifier: ^20.0.0
-        version: 20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2)
+        version: 20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0))(rxjs@7.8.2)
       '@angular/compiler':
         specifier: ^20.0.0
         version: 20.0.0
       '@angular/core':
         specifier: ^20.0.0
-        version: 20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.15.0)
+        version: 20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0)
       '@angular/platform-browser':
         specifier: ^20.0.0
-        version: 20.0.0(@angular/animations@20.0.0(@angular/common@20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.15.0)))(@angular/common@20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.15.0))
+        version: 20.0.0(@angular/animations@20.0.0(@angular/common@20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0))(rxjs@7.8.2))(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0)))(@angular/common@20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0))(rxjs@7.8.2))(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0))
+      '@angular/platform-server':
+        specifier: ^20.0.0
+        version: 20.3.15(@angular/common@20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0))(rxjs@7.8.2))(@angular/compiler@20.0.0)(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0))(@angular/platform-browser@20.0.0(@angular/animations@20.0.0(@angular/common@20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0))(rxjs@7.8.2))(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0)))(@angular/common@20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0))(rxjs@7.8.2))(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0)))(rxjs@7.8.2)
       '@tanstack/query-test-utils':
         specifier: workspace:*
         version: link:../query-test-utils
       '@testing-library/angular':
         specifier: ^18.0.0
-        version: 18.0.0(b638270d50b9f611fb362719c9f1adf5)
+        version: 18.0.0(c06d8d4c2ce1594f4574b3aa35a1592e)
       npm-run-all2:
         specifier: ^5.0.0
         version: 5.0.2
@@ -2293,6 +2296,9 @@ importers:
       vite-tsconfig-paths:
         specifier: ^5.1.4
         version: 5.1.4(typescript@5.8.3)(vite@6.4.1(@types/node@22.15.3)(jiti@2.5.1)(less@4.3.0)(lightningcss@1.30.1)(sass@1.88.0)(terser@5.39.1)(tsx@4.20.1)(yaml@2.8.1))
+      zone.js:
+        specifier: ^0.16.0
+        version: 0.16.0
     optionalDependencies:
       '@tanstack/query-devtools':
         specifier: workspace:*
@@ -3023,6 +3029,16 @@ packages:
       '@angular/animations':
         optional: true
 
+  '@angular/platform-server@20.3.15':
+    resolution: {integrity: sha512-OB3/ztCREeZ0pe2P+43Nah9Xq2Y79fN6mbsOY1JwwYxkM8ZN1WkSP11xlHHwAcoquHP7uFPhXwJqgTHBqGqkcw==}
+    engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
+    peerDependencies:
+      '@angular/common': 20.3.15
+      '@angular/compiler': 20.3.15
+      '@angular/core': 20.3.15
+      '@angular/platform-browser': 20.3.15
+      rxjs: ^6.5.3 || ^7.4.0
+
   '@angular/router@20.0.0':
     resolution: {integrity: sha512-RQ7rU4NaZDSvvOfMZQmB50q7de+jrHYb+f0ExLKBvr80B1MK3oc9VvI2BzBkGfM4aGx71MMa0UizjOiT/31kqw==}
     engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
@@ -15372,6 +15388,7 @@ packages:
   whatwg-encoding@3.1.1:
     resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==}
     engines: {node: '>=18'}
+    deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation
 
   whatwg-fetch@3.6.20:
     resolution: {integrity: sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==}
@@ -15527,6 +15544,10 @@ packages:
     resolution: {integrity: sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==}
     engines: {node: '>=12'}
 
+  xhr2@0.2.1:
+    resolution: {integrity: sha512-sID0rrVCqkVNUn8t6xuv9+6FViXjUVXq8H5rWOH2rz9fDNQEd4g0EA2XlcEdJXRz5BMEn4O1pJFdT+z4YHhoWw==}
+    engines: {node: '>= 6'}
+
   xml-name-validator@4.0.0:
     resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==}
     engines: {node: '>=12'}
@@ -15676,6 +15697,9 @@ packages:
   zone.js@0.15.0:
     resolution: {integrity: sha512-9oxn0IIjbCZkJ67L+LkhYWRyAy7axphb3VgE2MBDlOqnmHMPWGYMxJxBYFueFq/JGY2GMwS0rU+UCLunEmy5UA==}
 
+  zone.js@0.16.0:
+    resolution: {integrity: sha512-LqLPpIQANebrlxY6jKcYKdgN5DTXyyHAKnnWWjE5pPfEQ4n7j5zn7mOEEpwNZVKGqx3kKKmvplEmoBrvpgROTA==}
+
   zwitch@2.0.4:
     resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
 
@@ -15746,7 +15770,14 @@ snapshots:
       '@angular/core': 20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.15.0)
       tslib: 2.8.1
 
-  '@angular/build@20.0.0(8379d9408f101aa649c5ec9eae189324)':
+  '@angular/animations@20.0.0(@angular/common@20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0))(rxjs@7.8.2))(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0))':
+    dependencies:
+      '@angular/common': 20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0))(rxjs@7.8.2)
+      '@angular/core': 20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0)
+      tslib: 2.8.1
+    optional: true
+
+  '@angular/build@20.0.0(e7d71ef5d6f07f95ae57395d944dd75a)':
     dependencies:
       '@ampproject/remapping': 2.3.0
       '@angular-devkit/architect': 0.2000.0(chokidar@4.0.3)
@@ -15781,6 +15812,7 @@ snapshots:
     optionalDependencies:
       '@angular/core': 20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.15.0)
       '@angular/platform-browser': 20.0.0(@angular/animations@20.0.0(@angular/common@20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.15.0)))(@angular/common@20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.15.0))
+      '@angular/platform-server': 20.3.15(@angular/common@20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/compiler@20.0.0)(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.15.0))(@angular/platform-browser@20.0.0(@angular/animations@20.0.0(@angular/common@20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.15.0)))(@angular/common@20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.15.0)))(rxjs@7.8.2)
       less: 4.3.0
       lmdb: 3.3.0
       postcss: 8.5.6
@@ -15829,6 +15861,12 @@ snapshots:
       rxjs: 7.8.2
       tslib: 2.8.1
 
+  '@angular/common@20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0))(rxjs@7.8.2)':
+    dependencies:
+      '@angular/core': 20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0)
+      rxjs: 7.8.2
+      tslib: 2.8.1
+
   '@angular/compiler-cli@20.0.0(@angular/compiler@20.0.0)(typescript@5.8.3)':
     dependencies:
       '@angular/compiler': 20.0.0
@@ -15857,6 +15895,14 @@ snapshots:
       '@angular/compiler': 20.0.0
       zone.js: 0.15.0
 
+  '@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0)':
+    dependencies:
+      rxjs: 7.8.2
+      tslib: 2.8.1
+    optionalDependencies:
+      '@angular/compiler': 20.0.0
+      zone.js: 0.16.0
+
   '@angular/forms@20.0.0(@angular/common@20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.15.0))(@angular/platform-browser@20.0.0(@angular/animations@20.0.0(@angular/common@20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.15.0)))(@angular/common@20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.15.0)))(rxjs@7.8.2)':
     dependencies:
       '@angular/common': 20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2)
@@ -15873,6 +15919,35 @@ snapshots:
     optionalDependencies:
       '@angular/animations': 20.0.0(@angular/common@20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.15.0))
 
+  '@angular/platform-browser@20.0.0(@angular/animations@20.0.0(@angular/common@20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0))(rxjs@7.8.2))(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0)))(@angular/common@20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0))(rxjs@7.8.2))(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0))':
+    dependencies:
+      '@angular/common': 20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0))(rxjs@7.8.2)
+      '@angular/core': 20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0)
+      tslib: 2.8.1
+    optionalDependencies:
+      '@angular/animations': 20.0.0(@angular/common@20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0))(rxjs@7.8.2))(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0))
+
+  '@angular/platform-server@20.3.15(@angular/common@20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/compiler@20.0.0)(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.15.0))(@angular/platform-browser@20.0.0(@angular/animations@20.0.0(@angular/common@20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.15.0)))(@angular/common@20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.15.0)))(rxjs@7.8.2)':
+    dependencies:
+      '@angular/common': 20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2)
+      '@angular/compiler': 20.0.0
+      '@angular/core': 20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.15.0)
+      '@angular/platform-browser': 20.0.0(@angular/animations@20.0.0(@angular/common@20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.15.0)))(@angular/common@20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.15.0))
+      rxjs: 7.8.2
+      tslib: 2.8.1
+      xhr2: 0.2.1
+    optional: true
+
+  '@angular/platform-server@20.3.15(@angular/common@20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0))(rxjs@7.8.2))(@angular/compiler@20.0.0)(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0))(@angular/platform-browser@20.0.0(@angular/animations@20.0.0(@angular/common@20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0))(rxjs@7.8.2))(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0)))(@angular/common@20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0))(rxjs@7.8.2))(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0)))(rxjs@7.8.2)':
+    dependencies:
+      '@angular/common': 20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0))(rxjs@7.8.2)
+      '@angular/compiler': 20.0.0
+      '@angular/core': 20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0)
+      '@angular/platform-browser': 20.0.0(@angular/animations@20.0.0(@angular/common@20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0))(rxjs@7.8.2))(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0)))(@angular/common@20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0))(rxjs@7.8.2))(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0))
+      rxjs: 7.8.2
+      tslib: 2.8.1
+      xhr2: 0.2.1
+
   '@angular/router@20.0.0(@angular/common@20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.15.0))(@angular/platform-browser@20.0.0(@angular/animations@20.0.0(@angular/common@20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.15.0)))(@angular/common@20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.15.0)))(rxjs@7.8.2)':
     dependencies:
       '@angular/common': 20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2)
@@ -15881,6 +15956,14 @@ snapshots:
       rxjs: 7.8.2
       tslib: 2.8.1
 
+  '@angular/router@20.0.0(@angular/common@20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0))(rxjs@7.8.2))(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0))(@angular/platform-browser@20.0.0(@angular/animations@20.0.0(@angular/common@20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0))(rxjs@7.8.2))(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0)))(@angular/common@20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0))(rxjs@7.8.2))(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0)))(rxjs@7.8.2)':
+    dependencies:
+      '@angular/common': 20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0))(rxjs@7.8.2)
+      '@angular/core': 20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0)
+      '@angular/platform-browser': 20.0.0(@angular/animations@20.0.0(@angular/common@20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0))(rxjs@7.8.2))(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0)))(@angular/common@20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0))(rxjs@7.8.2))(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0))
+      rxjs: 7.8.2
+      tslib: 2.8.1
+
   '@arethetypeswrong/cli@0.15.3':
     dependencies:
       '@arethetypeswrong/core': 0.15.1
@@ -20108,6 +20191,15 @@ snapshots:
       '@testing-library/dom': 10.4.0
       tslib: 2.8.1
 
+  '@testing-library/angular@18.0.0(c06d8d4c2ce1594f4574b3aa35a1592e)':
+    dependencies:
+      '@angular/common': 20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0))(rxjs@7.8.2)
+      '@angular/core': 20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0)
+      '@angular/platform-browser': 20.0.0(@angular/animations@20.0.0(@angular/common@20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0))(rxjs@7.8.2))(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0)))(@angular/common@20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0))(rxjs@7.8.2))(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0))
+      '@angular/router': 20.0.0(@angular/common@20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0))(rxjs@7.8.2))(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0))(@angular/platform-browser@20.0.0(@angular/animations@20.0.0(@angular/common@20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0))(rxjs@7.8.2))(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0)))(@angular/common@20.0.0(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0))(rxjs@7.8.2))(@angular/core@20.0.0(@angular/compiler@20.0.0)(rxjs@7.8.2)(zone.js@0.16.0)))(rxjs@7.8.2)
+      '@testing-library/dom': 10.4.0
+      tslib: 2.8.1
+
   '@testing-library/dom@10.4.0':
     dependencies:
       '@babel/code-frame': 7.27.1
@@ -31029,6 +31121,8 @@ snapshots:
 
   xdg-basedir@5.1.0: {}
 
+  xhr2@0.2.1: {}
+
   xml-name-validator@4.0.0: {}
 
   xml-name-validator@5.0.0: {}
@@ -31163,4 +31257,6 @@ snapshots:
 
   zone.js@0.15.0: {}
 
+  zone.js@0.16.0: {}
+
   zwitch@2.0.4: {}
