Repository navigation
CGT higher and additional band split ignores taxable income above the basic rate limit #2432
Description
What's wrong
capital_gains_tax splits gains above the basic rate band between the higher and additional CGT bands at the income tax higher rate limit, but it gives every gainer the whole higher band (higher_rate_limit - basic_rate_limit, £87,440 in 2025-26). It never subtracts taxable income that already sits above the basic rate limit.
In policyengine_uk/variables/gov/hmrc/capital_gains_tax/capital_gains_tax.py:
higher_rate_band = higher_rate_limit - basic_rate_limit
...
band_left = higher_rate_band
for name in higher_order:
inside_higher[name], above_higher[name], band_left = _take(above_basic[name], band_left)So someone with £200,000 of taxable income has their gains charged at the CGT higher rate, not the additional rate, even though their income alone is already £74,860 above the higher rate limit.
Worked examples (2025-26, on main)
£200,000 of earnings and £50,000 of gains (47,000 above the £3,000 annual exempt amount; the personal allowance is fully withdrawn):
| Reform | Main | Correct |
|---|---|---|
| Current law (18% / 24% / 24%) | £11,280 | £11,280 |
| CGT additional rate 45% | £11,280 (unchanged) | £21,150 (47,000 x 45%) |
| CGT higher rate 45% | £21,150 | £11,280 (no higher band left) |
£100,000 of taxable income and £100,000 of gains, additional rate at 45%: the higher band left is 125,140 - 100,000 = £25,140, so CGT should be 25,140 x 24% + 71,860 x 45% = £38,370.60. Main charges 87,440 x 24% + 9,560 x 45% = £25,287.60.
Law and stacking
Under TCGA 1992 s. 1H(3) gains are charged at 18% or 24%, and s. 1I decides which by treating gains as the top slice of income: the lower rate applies only to the part within the unused basic rate band. Current law has no separate additional CGT rate. The model's additional_rate parameters (main, residential property, carried interest) equal the higher rate at every date and exist only so reforms can mirror the income tax additional-rate band, as the variable's documentation says.
For that split to mirror income tax, gains must stack on top of taxable income in the higher band too. The first pound of gains above the basic rate band sits at taxable income or the basic rate limit, whichever is higher, so the higher band left for gains is:
max_(higher_rate_limit - max_(taxable_income, basic_rate_limit), 0)Relief (BADR / investors' relief), residential property and carried interest gains share the same loop and band, so they have the same problem; the fix covers all of them.
Impact
- Current-law CGT is unaffected (beyond float32 rounding), because the higher and additional CGT rates are equal.
- Any reform that sets the CGT higher and additional rates apart is mis-scored: raising only the additional rate misses gainers whose income is above the higher rate limit, and raising only the higher rate wrongly charges them.
- With a realisation response that answers the rate on the last pound of gains (as in the stacked default-response PR Make a retention-rate elasticity of 1 the default CGT realisation response #2419), the wrong marginal band also drives the wrong behavioural response.
🤖 Generated with Claude Code
Activity