Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions changelog.d/2318.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- Charge VAT at the standard rate on private school fees from 1 January 2025 (Finance Act 2025 ss.47 and 49), through the new `gov.hmrc.vat.private_school_fees_exempt` parameter. The contributed rate `gov.contrib.labour.private_school_vat` now raises the rate rather than adding to it, so reforms that set it to 20% score nothing from 2025. Household taxes include private school VAT as a change from baseline (`private_school_vat_change`), as they do VAT; government tax revenue includes the level.
- Allocate school-fee VAT out of receipt-calibrated general VAT before counting it separately: general VAT is gross VAT less private school fees' official share of VAT receipts (new parameter `gov.simulation.vat.private_school_share_of_receipts`, HMRC's OBR-certified costing over OBR VAT receipts). No household's general VAT is made negative, school-specific reforms move only private school VAT, and standard-rate reforms move each head once.
139 changes: 135 additions & 4 deletions docs/engineering/vat-coverage.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
`vat` and `baseline_vat` compute the statutory liability on each household's
recorded consumption (the standard rate on `full_rate_vat_consumption` plus
the reduced rate on `reduced_rate_vat_consumption`) and divide it by two
factors, so that total VAT matches receipts:
factors. This gross amount, plus VAT on households' energy bills (see
[Energy bills are not grossed up](#energy-bills-are-not-grossed-up)), is
calibrated to total VAT receipts. The private school component is then
allocated to `private_school_vat`, as explained below, so the receipts
comparison uses `vat + private_school_vat`:

- `gov.simulation.vat.household_share_of_receipts` (0.7): the share of VAT
liabilities that falls on household final consumption. HMRC's VAT gap
Expand Down Expand Up @@ -68,8 +72,17 @@ product = pre-scaling VAT / OBR VAT receipts (same year)
survey coverage = product / household share (0.7)
```

`vat` divides each household's statutory VAT by the product, so total `vat`
equals receipts when the product matches the dataset.
Dividing each household's statutory VAT by the product gives the gross
amount, `G`; VAT on energy bills, `E`, is added to it without grossing (see
[Energy bills are not grossed up](#energy-bills-are-not-grossed-up)). At
current law, total `vat + private_school_vat` is close to `G + E` but not
equal to it: combined receipts are
`(1 - s) * sum(w * G) + sum(w * E) + sum(w * P0)` (see the receipt-partition
derivation below), so they differ from `G + E` by
`sum(w * P0) - s * sum(w * G)`. On the certified Enhanced FRS
(policyengine-uk-data 1.58.1) that difference is -£5.5m to -£142.5m a year from
2025-26 to 2031-32, at most 0.06% of VAT (Aggregate impact run
[40116746457](https://github.com/PolicyEngine/policyengine-uk/actions/runs/40116746457)).

### Results

Expand All @@ -88,7 +101,11 @@ equals receipts when the product matches the dataset.
The parameter takes the Microcosm 2024-25 value, 0.67 (product 0.469), the
latest outturn year.

With that product, total `vat` against receipts is:
With that product, the gross amount against receipts was as below, before
energy bills were split out. On the certified Enhanced FRS
(policyengine-uk-data 1.58.1), current-law `vat + private_school_vat` is
within 0.06% of the receipt-calibrated `G + E` (see above); the other rows
weren't checked against that bound:

| Dataset | 2024-25 | 2025-26 | 2026-27 |
|---|---|---|---|
Expand Down Expand Up @@ -148,6 +165,7 @@ For Enhanced FRS, download `enhanced_frs_2024_25.h5` from the model repository

## Energy bills are not grossed up


VAT on domestic electricity and gas is charged on each household's own bills
(`domestic_energy_vat`, PolicyEngine/policyengine-uk#2166), and the ONS domestic
fuel and power share of spending comes out of the generic reduced-rate share.
Expand Down Expand Up @@ -197,3 +215,116 @@ it is 38% (1.56.16) or 44% (1.58.0) above 2024-25 receipts.
To reproduce, run the snippet above on this version and subtract
`sim.calculate("domestic_energy_vat", year).sum()` from the receipts before
dividing.

## Private school VAT: splitting the existing receipts total

The OBR VAT total already includes VAT on private school fees. HMRC's
[VAT-only costing](https://www.gov.uk/government/publications/vat-on-private-school-fees/applying-vat-to-private-school-fees)
(Autumn Budget 2024 Table 5.1, certified by the OBR) is £460m in 2024-25,
£1,505m in 2025-26, £1,560m in 2026-27, £1,610m in 2027-28, £1,665m in
2028-29 and £1,725m in 2029-30. Adding a separate school VAT head to the
gross amount above would count that receipt twice. The model instead takes
the fees' share of receipts out of the gross amount, keeping the survey
coverage at 0.67.

For each household, let `G` be the grossed-up VAT on recorded consumption
other than energy bills (the statutory liability divided by the two factors),
`E` be `domestic_energy_vat`, `s` be
`gov.simulation.vat.private_school_share_of_receipts`, `P0` be
`baseline_private_school_vat` (baseline policy with this simulation's
attendance, fee and VAT-basis assumptions) and `P` be `private_school_vat`:

```text
vat = G * (1 - s) + E
baseline_vat = G0 * (1 - s) + E0
combined VAT = vat + P
```

The share comes out of `G` only. School fees are not energy bills, and `E`
is not grossed up, so a reform to the VAT on energy bills changes `vat` by
exactly the change in `E`.

`s` is the costing divided by OBR cash-basis VAT receipts for the same
fiscal year (March 2026 EFO, table 3.8):

| Fiscal year | School-fee VAT (£m) | VAT receipts (£m) | Share |
|---|---:|---:|---:|
| 2025-26 | 1,505 | 180,169 | 0.8353% |
| 2026-27 | 1,560 | 187,704 | 0.8311% |
| 2027-28 | 1,610 | 195,923 | 0.8218% |
| 2028-29 | 1,665 | 204,591 | 0.8138% |
| 2029-30 | 1,725 | 213,118 | 0.8094% |

The 2029-30 share is held after it. Each value starts on 1 April, so a model
year reads its fiscal year's share. `vat` and `baseline_vat` both read it
from the simulation's own parameters, as `baseline_private_school_vat` reads
its assumptions; the baseline parameter tree reads 1 January, before the
fiscal year's value takes effect.

Properties of the split:

- Because `0 <= s < 1` and `E` does not depend on `s`, the allocation never
makes a household's VAT negative where `G` and `E` are non-negative, and
repealing the school charge cannot either.
- `vat` reads neither attendance nor fees. Restoring the school exemption sets
`P` to zero and leaves `vat` unchanged, so receipts fall by the weighted
school charge, `sum(w * P0)`, with no second grossing factor. A contributed
rate moves only `P`.
- A standard-rate change moves `G * (1 - s)` and `P`, each on its own base:
recorded consumption and the fees. `E` moves only with the domestic
electricity and reduced rates.
- With household weights `w`, current-law combined receipts are
`sum(w * G) - s * sum(w * G) + sum(w * E) + sum(w * P0)`. They equal the
receipt-calibrated total `sum(w * G) + sum(w * E)` when the population's
school charge is the share `s` of its grossed-up VAT, and otherwise differ
from it by `sum(w * P0) - s * sum(w * G)`.
- `s` is a share of total receipts, but `G` is calibrated to receipts net of
energy-bill VAT. Where `G` matches receipts net of energy-bill VAT exactly,
`s * sum(w * G)` falls short of the costing by `s` times energy-bill VAT:
on `f9d1922c`'s 2025-26 energy-bill VAT, 0.8353% of £2.01bn, about £17m
(arithmetic on the energy table above, not a run).

The earlier design subtracted each household's own school charge from its
own gross VAT. Combined receipts then equalled `G` household by household,
but a pupil with little recorded consumption had negative general VAT, which
a repeal left in place. On the certified Enhanced FRS (policyengine-uk-data
1.58.1), before energy bills were split out, that made general VAT negative
for 549 households with non-negative gross VAT in 2025-26 (306,750 weighted
households, -£0.58bn), rising to 572 in 2030-31.

A share measured on each simulation's own population,
`sum(w * P0) / sum(w * G)`, would preserve combined receipts exactly, and was
considered. It makes every household's general VAT depend on the imputed
attendance of every other household, and attendance is imputed from net
income. Raising any household's income tax, National Insurance or council tax
could then move every household's VAT, by its gross VAT times the change in
the share. The aggregate-impact counted-once check fails a head wherever such
a response is one for one, as it did for `vat` in fewer than 10 households
under the earlier design; spreading the response to every household makes
that coincidence likelier. A household situation would also measure its own
school charge against its own VAT. The official share keeps each household's
VAT a function of its own consumption.

Measured on the certified Enhanced FRS (Aggregate impact run
[40116746457](https://github.com/PolicyEngine/policyengine-uk/actions/runs/40116746457)),
the official share changes current-law combined receipts by -£0.14bn in
2025-26, -£0.13bn in 2026-27, -£0.10bn in 2027-28, -£0.08bn in 2028-29 and
-£0.01bn in 2029-30, at most 0.06% of that dataset's VAT. Two overstatements
nearly offset there: VAT is 40% above OBR receipts (£252.5bn against
£180.2bn in 2025-26), and the modelled school charge is £1.95bn, against
HMRC's £1.505bn, because
attendance is imputed for 751,000 weighted pupils (policyengine-uk-data issue
568). The difference belongs to those two calibrations, not to the split.

The receipts check for the coverage factor is unchanged. Model year 2024 has
no school charge and a zero share, so, using the rounded 2024-25 Microcosm
inputs in the energy table above, `79.23 / (0.67 * 0.7) + 1.99 = £170.924bn`,
compared with OBR's £170.994bn: about 0.04% below receipts. The existing
differences from receipts, including Enhanced FRS's larger overstatement, still require
dataset-specific calibration. Aggregate impact CI compares the combined VAT
report group against the PR's base.

Model year 2024 represents 2024-25 but reads annual policy before the
January 2025 commencement, so `P0` and the share are both zero for that
year. The £460m part-year receipt (0.27% of £170,994m) remains in general
VAT; this change does not model its separate timing.
95 changes: 73 additions & 22 deletions policyengine_uk/data/fiscal_partition.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@
# measure for. With the heads' obr_line values they account for every
# tax row of the table.
# overlap_guards[]: the places double counting could occur, and the
# property the tests check for each. The aggregate-impact report also
# property the tests check for each. overlapping_base records a receipt
# allocation between heads sharing an imputed base. The report also
# checks the geographic_exclusivity guards on the certified dataset.
# spending_heads[]: as tax_heads, without obr_line, obr_table_3_1 and
# payer, plus caseload (default true): whether reports count recipients.
Expand Down Expand Up @@ -119,9 +120,9 @@ totals:
label: Taxes borne by the household
description: >-
Taxes subtracted from household net income. VAT and employer NI enter
only as reform-induced changes (vat_change and the employer NI response
incidence), because baseline VAT and employer NI are not deducted from
the incomes the model starts from.
only as reform-induced changes (vat_change, private_school_vat_change
and the employer NI response incidence), because baseline VAT and
employer NI are not deducted from the incomes the model starts from.
dropped_when:
gov.contrib.abolish_council_tax:
- council_tax
Expand Down Expand Up @@ -237,7 +238,7 @@ tax_heads:

# Consumption
- id: vat
label: VAT
label: VAT excluding private school fees
variable: vat
entity: household
obr_line: Value added tax
Expand All @@ -247,12 +248,16 @@ tax_heads:
totals: [gov_tax]
sign: nonnegative
data_note: >-
Negative for 76 households on policyengine-uk-data 1.58.0
(enhanced_frs_2024_25) in every year from 2025 to 2030, -£72m weighted
in 2026: full_rate_vat_consumption is negative there because the
dataset's consumption (44 households) or full_rate_vat_expenditure_rate
(32 households) is negative. policyengine-uk-data issue 565. Measured
2026-10-11.
Grossed-up VAT on recorded consumption less private school fees'
official share of VAT receipts, which the separate school head counts,
plus VAT on energy bills. The share is below one, so the allocation
keeps the sign of the grossed-up amount. Negative for 76 households on
policyengine-uk-data 1.58.1 (enhanced_frs_2024_25) in every year from
2025 to 2031, -£55.7m weighted in 2026 (Aggregate impact run
40116746457, 2026-10-24). On 1.58.0 (measured 2026-10-11) it was also
76: full_rate_vat_consumption is negative there because the dataset's
consumption (44 households) or full_rate_vat_expenditure_rate (32
households) is negative. policyengine-uk-data issue 565.
- id: vat_change
label: Change in VAT from its baseline
variable: vat_change
Expand All @@ -268,6 +273,11 @@ tax_heads:
- head: vat
route: vat_change adds vat and subtracts baseline_vat
why: a change measure built from the level; the two are never in the same total
# Standard-rated from 1 January 2025: Finance Act 2025 s.47 inserts VATA
# 1994 Sch 9 Part 3, taking private school education, vocational training
# and closely related board and lodging out of the Group 6 exemption, for
# supplies on or after that date (s.49). Before it the head is zero unless
# the contributed reform rate is set.
- id: private_school_vat
label: VAT on private school fees
variable: private_school_vat
Expand All @@ -276,12 +286,8 @@ tax_heads:
obr_table_3_1: Value added tax
report_group: vat
payer: household
totals: [gov_tax, household_tax]
totals: [gov_tax]
sign: nonnegative
zero_at_baseline: expected
zero_at_baseline_note: >-
gov.contrib.labour.private_school_vat is 0 at current law in this
model, so the head is reform-only here.
reads:
- head: income_tax
route: private_school_vat -> attends_private_school -> income_tax
Expand All @@ -292,6 +298,30 @@ tax_heads:
- head: council_tax
route: private_school_vat -> attends_private_school -> household_benefits -> council_tax_benefit -> council_tax
why: as above
- id: private_school_vat_change
label: Change in private school VAT from its baseline
variable: private_school_vat_change
entity: household
obr_line: Value added tax
obr_table_3_1: Value added tax
report_group: vat
payer: household
totals: [household_tax]
sign: any
zero_at_baseline: expected
reads:
- head: private_school_vat
route: private_school_vat_change adds private_school_vat and subtracts baseline_private_school_vat
why: a change measure built from the level; the two are never in the same total
- head: income_tax
route: private_school_vat_change -> private_school_vat -> attends_private_school -> income_tax
why: attendance is imputed from income; it decides who attends, not how much tax is counted
- head: nics_individual
route: private_school_vat_change -> private_school_vat -> attends_private_school -> (net income) -> national_insurance
why: as above
- head: council_tax
route: private_school_vat_change -> private_school_vat -> attends_private_school -> household_benefits -> council_tax_benefit -> council_tax
why: as above
- id: fuel_duty
label: Fuel duties
variable: fuel_duty
Expand Down Expand Up @@ -645,6 +675,7 @@ exclusions:
- {variable: student_loan_repayment, kind: component, head: student_loan_repayments}
# Consumption
- {variable: baseline_vat, kind: baseline_measure, head: vat_change, note: "Subtracted inside vat_change."}
- {variable: baseline_private_school_vat, kind: baseline_measure, head: private_school_vat_change, note: "Subtracted inside private_school_vat_change."}
- {variable: beer_duty, kind: component, head: alcohol_duty}
- {variable: cider_duty, kind: component, head: alcohol_duty}
- {variable: sparkling_cider_duty, kind: component, head: alcohol_duty}
Expand Down Expand Up @@ -697,14 +728,30 @@ overlap_guards:
property: >-
Each allocates a different receipt by shareholding; none reads another.
corporate_tax_incidence sums two of them and is excluded.
- id: private_school_vat_level_and_change
kind: level_and_change
heads: [private_school_vat, private_school_vat_change]
property: >-
Never in the same total: the level is in gov_tax and the change in
household_tax, as for vat and vat_change. private_school_vat_change
reads private_school_vat.
- id: private_school_vat_and_vat
kind: possible_base_overlap
kind: overlapping_base
heads: [vat, private_school_vat]
property: >-
vat applies to imputed consumption; if that consumption includes school
fees, turning on private_school_vat would tax them twice. The head is
zero at baseline, so baseline totals are unaffected; check the
consumption imputation before costing a reform that sets it.
Grossed-up consumption VAT is fitted to receipts net of energy-bill
VAT, which include school-fee VAT. vat keeps gross VAT less the fees'
official share of receipts
(gov.simulation.vat.private_school_share_of_receipts), plus VAT on
energy bills, which bears no share; then gov_tax adds
private_school_vat. vat reads neither attendance nor fees, so
school-specific exemption and contributed rate reforms move only the
school head, and a standard-rate change moves each head on its own
base. At current law combined receipts change by the weighted school
charge less the share of weighted gross VAT. Both baseline measures
hold this simulation's fee, attendance and share assumptions fixed.
See test_private_school_vat_receipts.py and
docs/engineering/vat-coverage.md.
- id: council_tax_gross_and_reduction
kind: gross_and_net
heads: [council_tax]
Expand All @@ -729,11 +776,15 @@ overlap_guards:
here as well.
- id: eligibility_reads
kind: read_not_inclusion
heads: [tv_licence, private_school_vat]
heads: [tv_licence, private_school_vat, private_school_vat_change]
property: >-
These heads reach other heads of the same total only through
eligibility or imputation (see each head's reads). Raising the other
head by a small amount leaves them unchanged on the test population.
For the private school heads that check is vacuous: attendance is
imputed only on a dataset (on a situation it is zero or an input), so
a tax change moves them only through re-imputed attendance on the
microdata (policyengine-uk-data issue 568).

uncovered_receipts:
# Rows of Table A.5 with no household measure in the model.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
description: VAT rate applied to private schools.
description: Contributed reform rate of VAT on private school fees. The fees bear VAT at the higher of this rate and the statutory rate (the standard rate from 1 January 2025, when the exemption ended), so the reform can raise the rate but never charges VAT on the fees twice.
values:
2000-01-01: 0
metadata:
unit: /1
label: Private school VAT rate
period: year
label: Private school VAT rate (reform)
Loading
Loading