National Insurance#
National Insurance is a key component of the UK tax system. It primarily funds certain types of welfare and state benefits, including the State Pension. Here’s an overview of National Insurance:
NI has four main classes:
Class 1: Paid by employees and their employers. This is based on the employee’s earnings and is deducted directly from wages.
Class 2: Paid by self-employed people with profits above a certain threshold.
Class 3: Voluntary contributions, often made by people who want to fill gaps in their National Insurance record.
Class 4: Paid by self-employed people with profits above a certain threshold, in addition to Class 2 NICs.
Modelling#
PolicyEngine models each class separately, according to the table below.
Show code cell source
# @title
import pandas as pd
from tabulate import tabulate
data = {
"Class": ["Class 1", "Class 2", "Class 4"],
"Methodology & Basis": [
"Based on employment income. \n- Monthly and annual calculations.",
"Based on self-employment income. \n- Weekly flat rate.",
"Derived from self-employment income minus Class 1 employee NI.",
],
"Thresholds & Limits": [
"Primary Threshold, Upper Earnings Limit",
"Small Profits Threshold",
"Lower Profits Limit, Upper Profits Limit",
],
"Rate Application": [
"Main and Additional rates",
"Flat rate",
"Main and Additional rates",
],
"Reference": [
"Social Security Contributions and Benefits Act 1992 s. 8",
"Social Security and Benefits Act 1992 s. 11",
"Social Security and Benefits Act 1992 s. 15",
],
}
df = pd.DataFrame(data)
df
Class | Methodology & Basis | Thresholds & Limits | Rate Application | Reference | |
---|---|---|---|---|---|
0 | Class 1 | Based on employment income. \n- Monthly and an... | Primary Threshold, Upper Earnings Limit | Main and Additional rates | Social Security Contributions and Benefits Act... |
1 | Class 2 | Based on self-employment income. \n- Weekly fl... | Small Profits Threshold | Flat rate | Social Security and Benefits Act 1992 s. 11 |
2 | Class 4 | Derived from self-employment income minus Clas... | Lower Profits Limit, Upper Profits Limit | Main and Additional rates | Social Security and Benefits Act 1992 s. 15 |
Appendix#
The chart below shows all threshold parameters for each class of National Insurance.
from policyengine_uk.system import system
import plotly.express as px
from policyengine_core.charts import format_fig
from policyengine_core.parameters import Parameter
ni = system.parameters.gov.hmrc.national_insurance
threshold_parameters = [
ni.class_1.thresholds.lower_earnings_limit,
ni.class_1.thresholds.primary_threshold,
ni.class_1.thresholds.upper_earnings_limit,
ni.class_1.thresholds.secondary_threshold,
ni.class_2.small_profits_threshold,
ni.class_4.thresholds.lower_profits_limit,
ni.class_4.thresholds.upper_profits_limit,
]
rate_parameters = [
param
for param in ni.get_descendants()
if param not in threshold_parameters and isinstance(param, Parameter)
]
instants = [f"{2020 + i}-04-06" for i in range(0, 14)]
instant_values = []
values = []
is_thresholds = []
labels = []
for param in threshold_parameters:
for instant in instants:
instant_values.append(instant)
values.append(param(instant))
is_thresholds.append(True)
labels.append(param.metadata.get("label"))
for param in rate_parameters:
for instant in instants:
instant_values.append(instant)
values.append(param(instant))
is_thresholds.append(False)
labels.append(param.metadata.get("label"))
df = pd.DataFrame(
{
"Instant": instant_values,
"Value": values,
"Threshold": is_thresholds,
"Label": labels,
}
)
fig = px.line(
df[df["Threshold"] == True],
x="Instant",
y="Value",
color="Label",
)
fig.update_layout(
title="National Insurance thresholds over time",
# Put legend at bottom
legend=dict(
orientation="h",
yanchor="bottom",
y=-0.3,
xanchor="right",
x=1,
title="",
),
)
fig.update_traces(
line_shape="hv",
)
fig = format_fig(fig)
fig
The chart below shows all rate parameters for each class of National Insurance.
Show code cell source
fig = px.line(
df[df["Threshold"] == False][df.Value < 1], # Don't plot the flat rate,
x="Instant",
y="Value",
color="Label",
)
fig.update_layout(
title="National Insurance rates over time",
# Put legend at bottom
legend=dict(
orientation="h",
yanchor="bottom",
y=-0.3,
xanchor="right",
x=1,
title="",
),
)
fig.update_traces(
line_shape="hv",
)
fig = format_fig(fig)
fig