diff --git a/packages/desktop-client/src/components/autocomplete/CategoryAutocomplete.tsx b/packages/desktop-client/src/components/autocomplete/CategoryAutocomplete.tsx
index cd38afd5dc435b388d494a9cdc117fda1beebad3..41bc750bcb52ed6ccbdf6850e0919a8daaadc5d8 100644
--- a/packages/desktop-client/src/components/autocomplete/CategoryAutocomplete.tsx
+++ b/packages/desktop-client/src/components/autocomplete/CategoryAutocomplete.tsx
@@ -25,6 +25,7 @@ import { useSyncedPref } from '../../hooks/useSyncedPref';
 import { SvgSplit } from '../../icons/v0';
 import { useResponsive } from '../../ResponsiveProvider';
 import { type CSSProperties, theme, styles } from '../../style';
+import { useRolloverSheetValue } from '../budget/rollover/RolloverComponents';
 import { makeAmountFullStyle } from '../budget/util';
 import { Text } from '../common/Text';
 import { TextOneLine } from '../common/TextOneLine';
@@ -377,14 +378,17 @@ function CategoryItem({
     : {};
   const [budgetType = 'rollover'] = useSyncedPref('budgetType');
 
-  const balance = useSheetValue(
+  const balanceBinding =
     budgetType === 'rollover'
       ? rolloverBudget.catBalance(item.id)
-      : reportBudget.catBalance(item.id),
-  );
+      : reportBudget.catBalance(item.id);
+  const balance = useSheetValue<
+    'rollover-budget' | 'report-budget',
+    typeof balanceBinding
+  >(balanceBinding);
 
   const isToBeBudgetedItem = item.id === 'to-be-budgeted';
-  const toBudget = useSheetValue(rolloverBudget.toBudget);
+  const toBudget = useRolloverSheetValue(rolloverBudget.toBudget) ?? 0;
 
   return (
     <div
diff --git a/packages/desktop-client/src/components/budget/BalanceWithCarryover.tsx b/packages/desktop-client/src/components/budget/BalanceWithCarryover.tsx
index d90ae1f269ef1c484976a693e624b1c237f389bd..e3d018dad20e59a32abf1d817aada0d9849c3b05 100644
--- a/packages/desktop-client/src/components/budget/BalanceWithCarryover.tsx
+++ b/packages/desktop-client/src/components/budget/BalanceWithCarryover.tsx
@@ -21,11 +21,11 @@ type BalanceWithCarryoverProps = Omit<
   ComponentPropsWithoutRef<typeof CellValue>,
   'binding'
 > & {
-  carryover: Binding;
-  balance: Binding;
-  goal: Binding;
-  budgeted: Binding;
-  longGoal: Binding;
+  carryover: Binding<'rollover-budget', 'carryover'>;
+  balance: Binding<'rollover-budget', 'leftover'>;
+  goal: Binding<'rollover-budget', 'goal'>;
+  budgeted: Binding<'rollover-budget', 'budget'>;
+  longGoal: Binding<'rollover-budget', 'long-goal'>;
   disabled?: boolean;
   carryoverIndicator?: ({ style }: CarryoverIndicatorProps) => JSX.Element;
 };
diff --git a/packages/desktop-client/src/components/budget/report/BalanceMenu.tsx b/packages/desktop-client/src/components/budget/report/BalanceMenu.tsx
index 0673620ff3734c2f57700538483c2d2318da71ef..5917be96f451feff0ec2232cbe251df1f00f0dfc 100644
--- a/packages/desktop-client/src/components/budget/report/BalanceMenu.tsx
+++ b/packages/desktop-client/src/components/budget/report/BalanceMenu.tsx
@@ -3,7 +3,8 @@ import React, { type ComponentPropsWithoutRef } from 'react';
 import { reportBudget } from 'loot-core/src/client/queries';
 
 import { Menu } from '../../common/Menu';
-import { useSheetValue } from '../../spreadsheet/useSheetValue';
+
+import { useReportSheetValue } from './ReportComponents';
 
 type BalanceMenuProps = Omit<
   ComponentPropsWithoutRef<typeof Menu>,
@@ -18,7 +19,7 @@ export function BalanceMenu({
   onCarryover,
   ...props
 }: BalanceMenuProps) {
-  const carryover = useSheetValue(reportBudget.catCarryover(categoryId));
+  const carryover = useReportSheetValue(reportBudget.catCarryover(categoryId));
   return (
     <Menu
       {...props}
diff --git a/packages/desktop-client/src/components/budget/report/ReportComponents.tsx b/packages/desktop-client/src/components/budget/report/ReportComponents.tsx
index b0f2345343ac92af078edfe1fc0d52ce9ebac977..ff9f429b3a81205501be6144b96f064550a0f53c 100644
--- a/packages/desktop-client/src/components/budget/report/ReportComponents.tsx
+++ b/packages/desktop-client/src/components/budget/report/ReportComponents.tsx
@@ -12,15 +12,37 @@ import { Button } from '../../common/Button2';
 import { Popover } from '../../common/Popover';
 import { Text } from '../../common/Text';
 import { View } from '../../common/View';
-import { CellValue } from '../../spreadsheet/CellValue';
+import { type Binding, type SheetFields } from '../../spreadsheet';
+import { CellValue, type CellValueProps } from '../../spreadsheet/CellValue';
 import { useFormat } from '../../spreadsheet/useFormat';
-import { Field, SheetCell } from '../../table';
+import { useSheetValue } from '../../spreadsheet/useSheetValue';
+import { Field, SheetCell, type SheetCellProps } from '../../table';
 import { BalanceWithCarryover } from '../BalanceWithCarryover';
 import { makeAmountGrey } from '../util';
 
 import { BalanceMenu } from './BalanceMenu';
 import { BudgetMenu } from './BudgetMenu';
 
+export const useReportSheetValue = <
+  FieldName extends SheetFields<'report-budget'>,
+>(
+  binding: Binding<'report-budget', FieldName>,
+) => {
+  return useSheetValue(binding);
+};
+
+const ReportCellValue = <FieldName extends SheetFields<'report-budget'>>(
+  props: CellValueProps<'report-budget', FieldName>,
+) => {
+  return <CellValue {...props} />;
+};
+
+const ReportSheetCell = <FieldName extends SheetFields<'report-budget'>>(
+  props: SheetCellProps<'report-budget', FieldName>,
+) => {
+  return <SheetCell {...props} />;
+};
+
 const headerLabelStyle: CSSProperties = {
   flex: 1,
   padding: '0 5px',
@@ -40,7 +62,7 @@ export const BudgetTotalsMonth = memo(function BudgetTotalsMonth() {
     >
       <View style={headerLabelStyle}>
         <Text style={{ color: theme.pageTextLight }}>Budgeted</Text>
-        <CellValue
+        <ReportCellValue
           binding={reportBudget.totalBudgetedExpense}
           type="financial"
           style={{ color: theme.pageTextLight, fontWeight: 600 }}
@@ -51,7 +73,7 @@ export const BudgetTotalsMonth = memo(function BudgetTotalsMonth() {
       </View>
       <View style={headerLabelStyle}>
         <Text style={{ color: theme.pageTextLight }}>Spent</Text>
-        <CellValue
+        <ReportCellValue
           binding={reportBudget.totalSpent}
           type="financial"
           style={{ color: theme.pageTextLight, fontWeight: 600 }}
@@ -59,7 +81,7 @@ export const BudgetTotalsMonth = memo(function BudgetTotalsMonth() {
       </View>
       <View style={headerLabelStyle}>
         <Text style={{ color: theme.pageTextLight }}>Balance</Text>
-        <CellValue
+        <ReportCellValue
           binding={reportBudget.totalLeftover}
           type="financial"
           style={{ color: theme.pageTextLight, fontWeight: 600 }}
@@ -108,7 +130,7 @@ export const GroupMonth = memo(function GroupMonth({
           : theme.budgetHeaderOtherMonth,
       }}
     >
-      <SheetCell
+      <ReportSheetCell
         name="budgeted"
         width="flex"
         textAlign="right"
@@ -118,7 +140,7 @@ export const GroupMonth = memo(function GroupMonth({
           type: 'financial',
         }}
       />
-      <SheetCell
+      <ReportSheetCell
         name="spent"
         width="flex"
         textAlign="right"
@@ -129,7 +151,7 @@ export const GroupMonth = memo(function GroupMonth({
         }}
       />
       {!group.is_income && (
-        <SheetCell
+        <ReportSheetCell
           name="balance"
           width="flex"
           textAlign="right"
@@ -270,7 +292,7 @@ export const CategoryMonth = memo(function CategoryMonth({
             </Popover>
           </View>
         )}
-        <SheetCell
+        <ReportSheetCell
           name="budget"
           exposed={editing}
           focused={editing}
@@ -320,7 +342,7 @@ export const CategoryMonth = memo(function CategoryMonth({
           data-testid="category-month-spent"
           onClick={() => onShowActivity(category.id, month)}
         >
-          <CellValue
+          <ReportCellValue
             binding={reportBudget.catSumAmount(category.id)}
             type="financial"
             getStyle={makeAmountGrey}
diff --git a/packages/desktop-client/src/components/budget/report/budgetsummary/BudgetTotal.tsx b/packages/desktop-client/src/components/budget/report/budgetsummary/BudgetTotal.tsx
index 7edb74feeee23695e8f646dd9ec5bc1e91f91d5e..a19c936f17331def40b7c03a12212c86f95ba988 100644
--- a/packages/desktop-client/src/components/budget/report/budgetsummary/BudgetTotal.tsx
+++ b/packages/desktop-client/src/components/budget/report/budgetsummary/BudgetTotal.tsx
@@ -1,7 +1,6 @@
 // @ts-strict-ignore
 import React, {
   type CSSProperties,
-  type ComponentProps,
   type ComponentType,
   type ReactNode,
 } from 'react';
@@ -9,22 +8,29 @@ import React, {
 import { theme, styles } from '../../../../style';
 import { Text } from '../../../common/Text';
 import { View } from '../../../common/View';
+import { type SheetFields, type Binding } from '../../../spreadsheet';
 import { CellValue } from '../../../spreadsheet/CellValue';
 
-type BudgetTotalProps = {
+type BudgetTotalProps<
+  CurrentField extends SheetFields<'report-budget'>,
+  TargetField extends SheetFields<'report-budget'>,
+> = {
   title: ReactNode;
-  current: ComponentProps<typeof CellValue>['binding'];
-  target: ComponentProps<typeof CellValue>['binding'];
+  current: Binding<'report-budget', CurrentField>;
+  target: Binding<'report-budget', TargetField>;
   ProgressComponent: ComponentType<{ current; target }>;
   style?: CSSProperties;
 };
-export function BudgetTotal({
+export function BudgetTotal<
+  CurrentField extends SheetFields<'report-budget'>,
+  TargetField extends SheetFields<'report-budget'>,
+>({
   title,
   current,
   target,
   ProgressComponent,
   style,
-}: BudgetTotalProps) {
+}: BudgetTotalProps<CurrentField, TargetField>) {
   return (
     <View
       style={{
diff --git a/packages/desktop-client/src/components/budget/report/budgetsummary/ExpenseProgress.tsx b/packages/desktop-client/src/components/budget/report/budgetsummary/ExpenseProgress.tsx
index 3aeb331203991ac3e846e07b25eee107e595c93e..7d3a8aeda11d2304d3482dfdc0bc8886a493ecf0 100644
--- a/packages/desktop-client/src/components/budget/report/budgetsummary/ExpenseProgress.tsx
+++ b/packages/desktop-client/src/components/budget/report/budgetsummary/ExpenseProgress.tsx
@@ -1,19 +1,19 @@
-import React, { type ComponentProps } from 'react';
+import React from 'react';
 
 import { theme } from '../../../../style';
-import { type CellValue } from '../../../spreadsheet/CellValue';
-import { useSheetValue } from '../../../spreadsheet/useSheetValue';
+import { type Binding } from '../../../spreadsheet';
+import { useReportSheetValue } from '../ReportComponents';
 
 import { fraction } from './fraction';
 import { PieProgress } from './PieProgress';
 
 type ExpenseProgressProps = {
-  current: ComponentProps<typeof CellValue>['binding'];
-  target: ComponentProps<typeof CellValue>['binding'];
+  current: Binding<'report-budget', 'total-spent'>;
+  target: Binding<'report-budget', 'total-budgeted'>;
 };
 export function ExpenseProgress({ current, target }: ExpenseProgressProps) {
-  let totalSpent = useSheetValue(current) || 0;
-  const totalBudgeted = useSheetValue(target) || 0;
+  let totalSpent = useReportSheetValue(current) || 0;
+  const totalBudgeted = useReportSheetValue(target) || 0;
 
   // Reverse total spent, and also set a bottom boundary of 0 (in case
   // income goes into an expense category and it's "positive", don't
diff --git a/packages/desktop-client/src/components/budget/report/budgetsummary/Saved.tsx b/packages/desktop-client/src/components/budget/report/budgetsummary/Saved.tsx
index 883021b5efe7ee4ffbf2e7afa1ec1f0df0eb0e50..142f9b4772156d0d4ee4640683cb64a79bfe6232 100644
--- a/packages/desktop-client/src/components/budget/report/budgetsummary/Saved.tsx
+++ b/packages/desktop-client/src/components/budget/report/budgetsummary/Saved.tsx
@@ -11,16 +11,17 @@ import { Tooltip } from '../../../common/Tooltip';
 import { View } from '../../../common/View';
 import { PrivacyFilter } from '../../../PrivacyFilter';
 import { useFormat } from '../../../spreadsheet/useFormat';
-import { useSheetValue } from '../../../spreadsheet/useSheetValue';
 import { makeAmountFullStyle } from '../../util';
+import { useReportSheetValue } from '../ReportComponents';
 
 type SavedProps = {
   projected: boolean;
   style?: CSSProperties;
 };
 export function Saved({ projected, style }: SavedProps) {
-  const budgetedSaved = useSheetValue(reportBudget.totalBudgetedSaved) || 0;
-  const totalSaved = useSheetValue(reportBudget.totalSaved) || 0;
+  const budgetedSaved =
+    useReportSheetValue(reportBudget.totalBudgetedSaved) || 0;
+  const totalSaved = useReportSheetValue(reportBudget.totalSaved) || 0;
   const format = useFormat();
   const saved = projected ? budgetedSaved : totalSaved;
   const isNegative = saved < 0;
diff --git a/packages/desktop-client/src/components/budget/rollover/budgetsummary/ToBudgetMenu.tsx b/packages/desktop-client/src/components/budget/rollover/budgetsummary/ToBudgetMenu.tsx
index 34833347657b61dd8ab1dbd9fee4d474e7334217..c115e0747f551f931c972d40004ca33968b812dd 100644
--- a/packages/desktop-client/src/components/budget/rollover/budgetsummary/ToBudgetMenu.tsx
+++ b/packages/desktop-client/src/components/budget/rollover/budgetsummary/ToBudgetMenu.tsx
@@ -21,7 +21,7 @@ export function ToBudgetMenu({
   onResetHoldBuffer,
   ...props
 }: ToBudgetMenuProps) {
-  const toBudget = useRolloverSheetValue(rolloverBudget.toBudget);
+  const toBudget = useRolloverSheetValue(rolloverBudget.toBudget) ?? 0;
   const forNextMonth = useRolloverSheetValue(rolloverBudget.forNextMonth);
   const items = [
     ...(toBudget > 0
diff --git a/packages/desktop-client/src/components/modals/HoldBufferModal.tsx b/packages/desktop-client/src/components/modals/HoldBufferModal.tsx
index 801c435f717182eb691253ee1cb95434693efccf..9cc1ffb1379af131bbfdb8abd5d9581560d65b83 100644
--- a/packages/desktop-client/src/components/modals/HoldBufferModal.tsx
+++ b/packages/desktop-client/src/components/modals/HoldBufferModal.tsx
@@ -17,7 +17,7 @@ type HoldBufferModalProps = {
 };
 
 export function HoldBufferModal({ onSubmit }: HoldBufferModalProps) {
-  const available = useRolloverSheetValue(rolloverBudget.toBudget);
+  const available = useRolloverSheetValue(rolloverBudget.toBudget) ?? 0;
   const [amount, setAmount] = useState<number>(0);
 
   const _onSubmit = (newAmount: number) => {
diff --git a/packages/desktop-client/src/components/modals/ReportBudgetMenuModal.tsx b/packages/desktop-client/src/components/modals/ReportBudgetMenuModal.tsx
index b28976d6379e69cb0c295e6458cdaf0e3c8517f7..b842cd5dc2122c016f8947cf74992c8a456561e5 100644
--- a/packages/desktop-client/src/components/modals/ReportBudgetMenuModal.tsx
+++ b/packages/desktop-client/src/components/modals/ReportBudgetMenuModal.tsx
@@ -10,6 +10,7 @@ import { amountToInteger, integerToAmount } from 'loot-core/shared/util';
 import { useCategory } from '../../hooks/useCategory';
 import { type CSSProperties, theme, styles } from '../../style';
 import { BudgetMenu } from '../budget/report/BudgetMenu';
+import { useReportSheetValue } from '../budget/report/ReportComponents';
 import {
   Modal,
   ModalCloseButton,
@@ -19,7 +20,6 @@ import {
 import { Text } from '../common/Text';
 import { View } from '../common/View';
 import { FocusableAmountInput } from '../mobile/transactions/FocusableAmountInput';
-import { useSheetValue } from '../spreadsheet/useSheetValue';
 
 type ReportBudgetMenuModalProps = ComponentPropsWithoutRef<
   typeof BudgetMenu
@@ -42,7 +42,7 @@ export function ReportBudgetMenuModal({
     borderTop: `1px solid ${theme.pillBorder}`,
   };
 
-  const budgeted = useSheetValue(reportBudget.catBudgeted(categoryId));
+  const budgeted = useReportSheetValue(reportBudget.catBudgeted(categoryId));
   const category = useCategory(categoryId);
   const [amountFocused, setAmountFocused] = useState(false);
 
diff --git a/packages/desktop-client/src/components/modals/RolloverBudgetSummaryModal.tsx b/packages/desktop-client/src/components/modals/RolloverBudgetSummaryModal.tsx
index 5abfafef6c74ae559d7660660a9918f3dca000c3..0c64e62687afdce8e5a8af1248810e9e82a99c06 100644
--- a/packages/desktop-client/src/components/modals/RolloverBudgetSummaryModal.tsx
+++ b/packages/desktop-client/src/components/modals/RolloverBudgetSummaryModal.tsx
@@ -23,10 +23,11 @@ export function RolloverBudgetSummaryModal({
 }: RolloverBudgetSummaryModalProps) {
   const dispatch = useDispatch();
   const prevMonthName = format(prevMonth(month), 'MMM');
-  const sheetValue = useRolloverSheetValue({
-    name: rolloverBudget.toBudget,
-    value: 0,
-  });
+  const sheetValue =
+    useRolloverSheetValue({
+      name: rolloverBudget.toBudget,
+      value: 0,
+    }) ?? 0;
 
   const openTransferAvailableModal = () => {
     dispatch(
diff --git a/packages/desktop-client/src/components/spreadsheet/CellValue.tsx b/packages/desktop-client/src/components/spreadsheet/CellValue.tsx
index ef1228c79910d7d7943d7e036b98b42476c3fa89..dd96739e3657085568a717e4a8e42ef6f24d4617 100644
--- a/packages/desktop-client/src/components/spreadsheet/CellValue.tsx
+++ b/packages/desktop-client/src/components/spreadsheet/CellValue.tsx
@@ -26,7 +26,10 @@ export type CellValueProps<
   ['data-testid']?: string;
 };
 
-export function CellValue({
+export function CellValue<
+  SheetName extends SheetNames,
+  FieldName extends SheetFields<SheetName>,
+>({
   binding,
   type,
   formatter,
@@ -35,8 +38,7 @@ export function CellValue({
   privacyFilter,
   'data-testid': testId,
   ...props
-  // eslint-disable-next-line @typescript-eslint/no-explicit-any
-}: CellValueProps<any, any>) {
+}: CellValueProps<SheetName, FieldName>) {
   const { fullSheetName } = useSheetName(binding);
   const sheetValue = useSheetValue(binding);
   const format = useFormat();
diff --git a/packages/desktop-client/src/components/spreadsheet/index.ts b/packages/desktop-client/src/components/spreadsheet/index.ts
index 429e50441fa949b64d64f352ee7a8e7a7c5103fe..e9ff3d7aa7ac4136ea6d168406bd693a33e75e79 100644
--- a/packages/desktop-client/src/components/spreadsheet/index.ts
+++ b/packages/desktop-client/src/components/spreadsheet/index.ts
@@ -23,7 +23,7 @@ export type Spreadsheets = {
     'available-funds': number;
     'last-month-overspent': number;
     buffered: number;
-    'to-budget': number;
+    'to-budget': number | null;
     'from-last-month': number;
     'total-budgeted': number;
     'total-income': number;
@@ -39,6 +39,29 @@ export type Spreadsheets = {
     goal: number;
     'long-goal': number;
   };
+  'report-budget': {
+    // Common fields
+    'uncategorized-amount': number;
+    'uncategorized-balance': number;
+
+    // Report fields
+    'total-budgeted': number;
+    'total-budget-income': number;
+    'total-saved': number;
+    'total-income': number;
+    'total-spent': number;
+    'real-saved': number;
+    'total-leftover': number;
+    'group-sum-amount': number;
+    'group-budget': number;
+    'group-leftover': number;
+    budget: number;
+    'sum-amount': number;
+    leftover: number;
+    carryover: number;
+    goal: number;
+    'long-goal': number;
+  };
 };
 
 export type SheetNames = keyof Spreadsheets & string;
@@ -47,10 +70,8 @@ export type SheetFields<SheetName extends SheetNames> =
   keyof Spreadsheets[SheetName] & string;
 
 export type Binding<
-  // eslint-disable-next-line @typescript-eslint/no-explicit-any
-  SheetName extends SheetNames = any,
-  // eslint-disable-next-line @typescript-eslint/no-explicit-any
-  SheetFieldName extends SheetFields<SheetName> = any,
+  SheetName extends SheetNames,
+  SheetFieldName extends SheetFields<SheetName>,
 > =
   | SheetFieldName
   | {
diff --git a/packages/desktop-client/src/components/spreadsheet/useSheetName.ts b/packages/desktop-client/src/components/spreadsheet/useSheetName.ts
index 621efc523c6af1c838093970391a33eafc6a945d..2d5d287897756b062b1f73c118cf288e119fab46 100644
--- a/packages/desktop-client/src/components/spreadsheet/useSheetName.ts
+++ b/packages/desktop-client/src/components/spreadsheet/useSheetName.ts
@@ -3,7 +3,7 @@ import { useContext } from 'react';
 
 import { NamespaceContext } from './NamespaceContext';
 
-import { type Binding } from '.';
+import { type SheetNames, type SheetFields, type Binding } from '.';
 
 function unresolveName(name) {
   const idx = name.indexOf('!');
@@ -16,14 +16,17 @@ function unresolveName(name) {
   return { sheet: null, name };
 }
 
-export function useSheetName(binding: Binding) {
+export function useSheetName<
+  SheetName extends SheetNames,
+  FieldName extends SheetFields<SheetName>,
+>(binding: Binding<SheetName, FieldName>) {
   if (!binding) {
     throw new Error('Sheet binding is required');
   }
 
   const isStringBinding = typeof binding === 'string';
 
-  let bindingName = isStringBinding ? binding : binding.name;
+  let bindingName: string = isStringBinding ? binding : binding.name;
 
   if (global.IS_TESTING && !isStringBinding && !bindingName) {
     bindingName = binding.value.toString();
diff --git a/packages/desktop-client/src/components/spreadsheet/useSheetValue.ts b/packages/desktop-client/src/components/spreadsheet/useSheetValue.ts
index 1b6c5c0c5bcc9a2ef024cd860dc01ba319dacfae..62061fede0c528f959f643f7fa8af22ba229eda5 100644
--- a/packages/desktop-client/src/components/spreadsheet/useSheetValue.ts
+++ b/packages/desktop-client/src/components/spreadsheet/useSheetValue.ts
@@ -5,13 +5,26 @@ import { useSpreadsheet } from 'loot-core/src/client/SpreadsheetProvider';
 
 import { useSheetName } from './useSheetName';
 
-import { type Binding } from '.';
-
-export function useSheetValue(binding: Binding, onChange?: (result) => void) {
+import {
+  type Spreadsheets,
+  type SheetFields,
+  type SheetNames,
+  type Binding,
+} from '.';
+
+export function useSheetValue<
+  SheetName extends SheetNames,
+  FieldName extends SheetFields<SheetName>,
+>(
+  binding: Binding<SheetName, FieldName>,
+  onChange?: (result) => void,
+): Spreadsheets[SheetName][FieldName] {
   const { sheetName, fullSheetName } = useSheetName(binding);
 
   const bindingObj =
-    typeof binding === 'string' ? { name: binding, value: null } : binding;
+    typeof binding === 'string'
+      ? { name: binding, value: null, query: undefined }
+      : binding;
 
   const spreadsheet = useSpreadsheet();
   const [result, setResult] = useState({
diff --git a/packages/desktop-client/src/components/table.tsx b/packages/desktop-client/src/components/table.tsx
index 4d47f531511be770ba77939f30bd5ce9b63d8485..c62d6111b697c15cd82e508e9111d328d6d82751 100644
--- a/packages/desktop-client/src/components/table.tsx
+++ b/packages/desktop-client/src/components/table.tsx
@@ -705,10 +705,8 @@ export type SheetCellProps<
   textAlign?: CSSProperties['textAlign'];
 };
 export function SheetCell<
-  // eslint-disable-next-line @typescript-eslint/no-explicit-any
-  SheetName extends SheetNames = any,
-  // eslint-disable-next-line @typescript-eslint/no-explicit-any
-  FieldName extends SheetFields<SheetName> = any,
+  SheetName extends SheetNames,
+  FieldName extends SheetFields<SheetName>,
 >({
   valueProps,
   valueStyle,
diff --git a/packages/desktop-client/src/components/transactions/TransactionsTable.test.jsx b/packages/desktop-client/src/components/transactions/TransactionsTable.test.jsx
index 9debc52197d4630a0916c3047b64194541cb20bc..157c31c89ac9458c167da161a62ef917176f7754 100644
--- a/packages/desktop-client/src/components/transactions/TransactionsTable.test.jsx
+++ b/packages/desktop-client/src/components/transactions/TransactionsTable.test.jsx
@@ -28,7 +28,9 @@ import { ResponsiveProvider } from '../../ResponsiveProvider';
 import { TransactionTable } from './TransactionsTable';
 
 vi.mock('loot-core/src/platform/client/fetch');
-vi.mock('../../hooks/useFeatureFlag', () => vi.fn().mockReturnValue(false));
+vi.mock('../../hooks/useFeatureFlag', () => ({
+  default: vi.fn().mockReturnValue(false),
+}));
 
 const accounts = [generateAccount('Bank of America')];
 const payees = [
diff --git a/packages/loot-core/src/client/queries.ts b/packages/loot-core/src/client/queries.ts
index fef175374e07b7d4c619888308f267725211c41d..ec5e124977ca2ccf0fe588ecb46bb7598be18b05 100644
--- a/packages/loot-core/src/client/queries.ts
+++ b/packages/loot-core/src/client/queries.ts
@@ -26,6 +26,7 @@ type BudgetType<SheetName extends SheetNames> = Record<
 
 const accountParametrizedField = parametrizedField<'account'>();
 const rolloverParametrizedField = parametrizedField<'rollover-budget'>();
+const reportParametrizedField = parametrizedField<'report-budget'>();
 
 export function getAccountFilter(accountId: string, field = 'account') {
   if (accountId) {
@@ -294,16 +295,16 @@ export const reportBudget = {
   totalSaved: 'real-saved',
 
   totalLeftover: 'total-leftover',
-  groupSumAmount: id => `group-sum-amount-${id}`,
+  groupSumAmount: reportParametrizedField('group-sum-amount'),
   groupIncomeReceived: 'total-income',
 
-  groupBudgeted: id => `group-budget-${id}`,
-  groupBalance: id => `group-leftover-${id}`,
+  groupBudgeted: reportParametrizedField('group-budget'),
+  groupBalance: reportParametrizedField('group-leftover'),
 
-  catBudgeted: id => `budget-${id}`,
-  catSumAmount: id => `sum-amount-${id}`,
-  catBalance: id => `leftover-${id}`,
-  catCarryover: id => `carryover-${id}`,
-  catGoal: id => `goal-${id}`,
-  catLongGoal: id => `long-goal-${id}`,
-};
+  catBudgeted: reportParametrizedField('budget'),
+  catSumAmount: reportParametrizedField('sum-amount'),
+  catBalance: reportParametrizedField('leftover'),
+  catCarryover: reportParametrizedField('carryover'),
+  catGoal: reportParametrizedField('goal'),
+  catLongGoal: reportParametrizedField('long-goal'),
+} satisfies BudgetType<'report-budget'>;
diff --git a/upcoming-release-notes/3097.md b/upcoming-release-notes/3097.md
new file mode 100644
index 0000000000000000000000000000000000000000..46315010044a5a968659ec5c3fbe23f6cd4ca0c6
--- /dev/null
+++ b/upcoming-release-notes/3097.md
@@ -0,0 +1,6 @@
+---
+category: Maintenance
+authors: [jfdoming]
+---
+
+Support type-checking on spreadsheet fields (part 3)