Skip to content

Pre-tax health insurance premiums are also counted in itemized medical expenses #10064

Description

@MaxGhenis

itemized_medical_expenses counts a health insurance premium that was already excluded from wages as a section 125 pre-tax payroll deduction, so the same premium reduces taxable income twice.

What the model does (policyengine-us 2.2.1)

  • pre_tax_health_insurance_premiums is listed in gov.irs.gross_income.pre_tax_contributions, so irs_employment_income = max(0, employment_income - pre_tax_contributions) excludes it from wages (and fica_pre_tax_contributions excludes it from FICA wages).
  • medical_expense_health_insurance_premiums returns health_insurance_premiums when nonzero, otherwise health_insurance_premiums_without_medicare_part_b plus modeled Part B premiums. It does not subtract pre_tax_health_insurance_premiums.
  • itemized_medical_expenses adds medical_expense_health_insurance_premiums and other_medical_expenses.

Reproduction

Single filer in Texas, 2024, age 40, $60,000 of employment_income, $20,000 of other_medical_expenses, a $2,000 premium:

Case Inputs AGI itemized_medical_expenses income_tax
Premium paid after tax health_insurance_premiums_without_medicare_part_b = 2,000 60,000 22,000 4,692.93
Premium paid pre-tax, as the model computes it the above, plus pre_tax_health_insurance_premiums = 2,000 58,000 22,000 4,445.74
Premium paid pre-tax, excluded from the medical base pre_tax_health_insurance_premiums = 2,000 only 58,000 20,000 4,685.74

The second row is $240 below the third: the premium is excluded from wages and deducted again.

Law

IRC section 213(a) allows a deduction for medical expenses "paid during the taxable year, not compensated for by insurance or otherwise". A premium paid by salary reduction under a section 125 cafeteria plan is treated as an employer contribution excluded from gross income under section 106, so the employee has not paid it with taxed income. IRS Publication 502 ("Insurance Premiums", under "Employer-Sponsored Health Insurance Plan") says not to include premiums paid by an employer-sponsored health insurance plan "unless the premiums are included on your Form W-2", and gives the example of a federal employee whose share of the FEHB premium is paid before tax: it is not in gross income, so it cannot be deducted.

Why it matters now

No dataset populated pre_tax_health_insurance_premiums, so this was latent. PolicyEngine/microcosm#1189 starts producing it (about $180 billion, a subset of the premiums already carried in health_insurance_premiums_without_medicare_part_b). Only tax units that itemize with medical expenses above the 7.5% floor are affected.

Scope to check before changing the helper

medical_expense_health_insurance_premiums also feeds SNAP allowable medical expenses, HUD medical expenses, Medicaid medically-needy spend-down and several state deductions (Montana, Ohio, Missouri, Pennsylvania CCW and others). Those programs may count a premium the person paid whatever its tax treatment, so the fix probably belongs in the federal itemized path (and any state deduction that conforms to section 213), not in the shared helper.

Activity

  1. MaxGhenis commented on Oct 10, 2026

    @MaxGhenis
    ContributorAuthor

    Closing this as filed on a wrong premise.

    The engine treats the premium inputs as disjoint: a premium paid by pre-tax payroll deduction belongs only in pre_tax_health_insurance_premiums, and health_insurance_premiums, health_insurance_premiums_without_medicare_part_b and other_health_insurance_premiums hold the premiums not paid that way (#10046 documents this; #10067 pins Schedule A against it). Under that contract itemized_medical_expenses is already correct, and subtracting the pre-tax input there would undercount a caller who follows the contract.

    The second row of the table above supplied the same $2,000 in both sets, which is a data error, not an engine defect. The fix is on the data side: PolicyEngine/microcosm#1189 will not ship an overlapping pre-tax column, and the pre-tax producer will net its dollars out of the other premium inputs once an engine that includes #10046 is pinned.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions