Show code
library(tidyverse)
library(readxl)
library(janitor)
library(flextable)
set_flextable_defaults(
font.family = "Arial",
font.size = 10,
border.color = "#003865",
padding = 4
)Professor Emily Nordmann
March 9, 2026
AI declaration: Claude Opus 4.6 was used heavily in the writing and coding of this blog. I have spent a lot of time shaping, editing, and verifying Claude’s work, but Claude is primary author of everything except the conclusion. Which will be immediately obvious because that’s where I start swearing
Women now make up around a third of professors in UK higher education (HESA, 2025). That figure has been rising steadily and we can celebrate moving in the right direction if not yet being at the destination. But if women professors are disproportionately concentrated in teaching-focused roles, there’s an uncomfortable possiblity that women are being funneled into “less prestigious” teaching-focused roles. I don’t think teaching-focused roles are less prestigious and I normally refuse to even give that suggestion any air time but in this post, acknowledging the rhetoric is unavoidable.
This blog uses the HESA Staff Record data to look at who makes it to professor overall, the gender balance among all academics, how feminised teaching-focused work is at every career level, and finally whether that pattern holds specifically among professors.
A previous version of this post filtered the data to include only staff on open-ended/permanent contracts. This version uses all terms of employment instead, which makes it easier to compare across the different analyses and with HESA’s own published figures. The broad patterns are much the same, though some specific percentages have shifted slightly.
HESA classifies academic staff along two dimensions: their academic employment function (what kind of work they are contracted to do) and their contract level (their seniority).
Academic employment function describes the primary purpose of the role.
Contract level describes seniority within the institution.
This analysis draws on two HESA open datasets:
Table 9 (national-level): a single CSV covering all UK HE academic staff from 2014/15 to 2024/25. Each row is a count of staff for a particular combination of sex, academic employment function, contract level, salary source, mode of employment, terms, clinical status, and country. There is no aggregate row for salary source, so the code sums across all 23 categories.
Table 17 (institution-level): separate CSV files for each academic year from 2014/15 to 2024/25, with 12 metadata rows at the top. This table covers full-time staff only and includes a provider name column, which allows Russell Group vs non-Russell Group comparisons.
Counts are Full-Person Equivalent (FPE), rounded to the nearest 5. “Professor” refers to HESA contract level F1, which excludes professors in senior management roles. From 2022/23, the definition of “sex” changed from self-identification to legal documents. All figures in this post refer to staff of all modes of employment and all terms of employment unless stated otherwise. Staff totals in this analysis include only Female and Male categories (excluding “Other” and “Not known”) and only the three main academic functions (teaching only, research only, and both teaching and research), excluding staff with “Neither teaching nor research” function. This means totals will be slightly lower than HESA’s headline figures.
# ---- Read Table 9 ----
t9_files <- list.files("table-9/", full.names = TRUE)
read_t9 <- function(filepath) {
read_csv(filepath, skip = 12) |>
clean_names()
}
table9 <- map_dfr(t9_files, read_t9) |>
filter(
sex %in% c("Female", "Male"),
contract_levels %in% c("Professor", "Other senior academic",
"Other contract level"),
academic_employment_function %in% c(
"Teaching only", "Research only", "Both teaching and research"
),
mode_of_employment == "All",
country_of_he_provider == "All",
clinical_status == "All",
terms_of_employment == "All"
)
# ---- Read Table 17 (multiple Excel files) ----
t17_files <- list.files("table-17/", full.names = TRUE)
read_t17 <- function(filepath) {
read_csv(filepath, skip = 12) |>
clean_names()
}
table17 <- map_dfr(t17_files, read_t17)# ---- Russell Group ----
russell_group <- c(
"The University of Birmingham",
"The University of Bristol",
"The University of Cambridge",
"Cardiff University",
"Durham University",
"The University of Edinburgh",
"The University of Exeter",
"The University of Glasgow",
"Imperial College of Science, Technology and Medicine",
"King's College London",
"The University of Leeds",
"The University of Liverpool",
"The London School of Economics and Political Science",
"The University of Manchester",
"Newcastle University",
"The University of Nottingham",
"The University of Oxford",
"Queen Mary University of London",
"Queen's University Belfast",
"The University of Sheffield",
"The University of Southampton",
"University College London",
"The University of Warwick",
"The University of York"
)
# ---- Glasgow colours ----
uog_blue <- "#003865"
uog_pink <- "#AE2573"
uog_grey <- "#7F7F7F"
uog_green <- "#007A4D"
uog_black <- "#000000"
theme_uog <- function() {
theme_minimal(base_family = "Aptos", base_size = 12) +
theme(
plot.title = element_text(colour = uog_black, face = "bold", size = 14),
plot.subtitle = element_text(colour = uog_grey, size = 11),
axis.text.x = element_text(angle = 45, hjust = 1),
legend.position = "bottom",
panel.grid.minor = element_blank()
)
}
# ---- Flextable helper ----
ft_uog <- function(ft) {
ft |>
bg(part = "header", bg = uog_blue) |>
color(part = "header", color = "white") |>
bold(part = "header") |>
align(align = "center", part = "all") |>
align(j = 1, align = "left", part = "body") |>
border_remove() |>
hline_top(part = "header", border = officer::fp_border(color = uog_blue, width = 2)) |>
hline_bottom(part = "header", border = officer::fp_border(color = uog_blue, width = 1)) |>
hline_bottom(part = "body", border = officer::fp_border(color = uog_blue, width = 2)) |>
autofit()
}Before getting into contract type, it is worth establishing the baseline of how many academics hold a professorship at all, and whether this differs by gender and academic employment function.
# Total academics and professors, by sex and function
# Sum across salary source, filter to national totals
staff_totals <- table9 |>
group_by(academic_year, contract_levels, sex, academic_employment_function) |>
summarise(number = sum(number, na.rm = TRUE), .groups = "drop")
latest_year <- staff_totals |>
pull(academic_year) |>
max()
# --- Table 1: Overall % who are professors ---
overall_pct_prof <- staff_totals |>
filter(academic_year == latest_year) |>
group_by(sex) |>
summarise(
total_staff = sum(number),
professors = sum(number[contract_levels == "Professor"]),
.groups = "drop"
) |>
mutate(pct_professor = professors / total_staff * 100)
overall_all <- staff_totals |>
filter(academic_year == latest_year) |>
summarise(
total_staff = sum(number),
professors = sum(number[contract_levels == "Professor"])
) |>
mutate(sex = "All", pct_professor = professors / total_staff * 100)
tbl_overall <- bind_rows(overall_all, overall_pct_prof) |>
select(sex, total_staff, professors, pct_professor) |>
mutate(pct_professor = round(pct_professor, 1))Sex | Total academic staff | Professors | % who are professors |
|---|---|---|---|
All | 483,505 | 51,880 | 10.7 |
Female | 237,625 | 16,825 | 7.1 |
Male | 245,880 | 35,055 | 14.3 |
Roughly one in 10 academics is a professor. Men are considerably more likely than women to hold that title, and this is true before we even start to think about contract type. The pipeline narrows more sharply for women at the top.
It is also worth examining whether the gap differs by contract type, since women on teaching-focused contracts may be even less likely to reach professor than women on combined contracts.
# --- Table 2: % who are professors, by sex and academic function ---
pct_prof_by_track <- staff_totals |>
filter(academic_year == latest_year) |>
group_by(academic_employment_function) |>
summarise(
total_staff = sum(number),
professors = sum(number[contract_levels == "Professor"]),
.groups = "drop"
) |>
mutate(pct_professor = round(professors / total_staff * 100, 1))
# --- Table 3: % who are professors, by sex and academic function ---
pct_prof_by_function <- staff_totals |>
filter(academic_year == latest_year) |>
group_by(sex, academic_employment_function) |>
summarise(
total_staff = sum(number),
professors = sum(number[contract_levels == "Professor"]),
.groups = "drop"
) |>
mutate(pct_professor = round(professors / total_staff * 100, 1))pct_prof_by_track |>
select(academic_employment_function, total_staff, professors, pct_professor) |>
rename(
`Academic function` = academic_employment_function,
`Total staff` = total_staff,
Professors = professors,
`% who are professors` = pct_professor
) |>
flextable() |>
ft_uog() |>
colformat_num(j = c("Total staff", "Professors"), big.mark = ",", digits = 0)Academic function | Total staff | Professors | % who are professors |
|---|---|---|---|
Both teaching and research | 210,640 | 47,375 | 22.5 |
Research only | 103,855 | 2,110 | 2.0 |
Teaching only | 169,010 | 2,395 | 1.4 |
pct_prof_by_function |>
select(sex, academic_employment_function, total_staff, professors, pct_professor) |>
rename(
Sex = sex,
`Academic function` = academic_employment_function,
`Total staff` = total_staff,
Professors = professors,
`% who are professors` = pct_professor
) |>
flextable() |>
merge_v(j = "Sex") |>
ft_uog() |>
colformat_num(j = c("Total staff", "Professors"), big.mark = ",", digits = 0) |>
valign(j = "Sex", valign = "top")Sex | Academic function | Total staff | Professors | % who are professors |
|---|---|---|---|---|
Female | Both teaching and research | 93,640 | 15,030 | 16.1 |
Research only | 51,595 | 695 | 1.3 | |
Teaching only | 92,390 | 1,100 | 1.2 | |
Male | Both teaching and research | 117,000 | 32,345 | 27.6 |
Research only | 52,260 | 1,415 | 2.7 | |
Teaching only | 76,620 | 1,295 | 1.7 |
On traditional R&T contracts, a meaningful share of staff reach professor, though the gender gap is still huge. On teaching-focused contracts, professorships are very rare for everyone. Both women and men are much less likely to reach the top via a teaching-focused contract than a combined one.
Too see whether there are too few or too many women in teaching-only roles, we first need to establish what proportion of academic staff are women overall and how that changes with seniority.
# --- % female among all academic staff, by contract level, over time ---
all_by_level <- table9 |>
group_by(academic_year, contract_levels, sex) |>
summarise(number = sum(number, na.rm = TRUE), .groups = "drop")
pct_female_by_level <- all_by_level |>
group_by(academic_year, contract_levels) |>
mutate(total = sum(number), pct_female = number / total * 100) |>
filter(sex == "Female") |>
ungroup()ggplot(pct_female_by_level,
aes(x = academic_year, y = pct_female,
colour = contract_levels, group = contract_levels)) +
geom_line(linewidth = 1) +
geom_point(size = 2) +
geom_hline(yintercept = 50, linetype = "dashed", colour = uog_grey) +
scale_colour_manual(values = c(
"Professor" = uog_blue,
"Other senior academic" = uog_pink,
"Other contract level" = uog_grey
)) +
labs(
title = "% female by contract level",
subtitle = "UK HE sector over time (HESA Table 9)",
x = "Academic year", y = "% female", colour = "Contract level",
caption = "Dashed line = parity"
) +
theme_uog()pct_female_by_level |>
filter(academic_year == latest_year) |>
mutate(pct_female = round(pct_female, 1)) |>
select(contract_levels, number, total, pct_female) |>
rename(
`Contract level` = contract_levels,
`Female staff (FPE)` = number,
`All staff (FPE)` = total,
`% female` = pct_female
) |>
flextable() |>
ft_uog() |>
colformat_num(j = c("Female staff (FPE)", "All staff (FPE)"), big.mark = ",", digits = 0)Contract level | Female staff (FPE) | All staff (FPE) | % female |
|---|---|---|---|
Other contract level | 215,555 | 419,840 | 51.3 |
Other senior academic | 5,245 | 11,785 | 44.5 |
Professor | 16,825 | 51,880 | 32.4 |
Women make up a near-equal share of the most junior academic staff, but their representation falls steadily as seniority increases. By professor grade, women account for roughly a third. This gap has been closing, but slowly. The higher up the ladder, the fewer women there are.
Teaching-focused work across the sector is majority-female. This section examines whether that holds at every level of seniority.
# All contract levels, by function and sex (summing across salary source)
all_staff <- table9 |>
filter(
sex %in% c("Female", "Male"),
academic_employment_function %in% c(
"Teaching only", "Research only", "Both teaching and research"
),
contract_levels %in% c("Professor", "Other senior academic",
"Other contract level"),
mode_of_employment == "All",
country_of_he_provider == "All",
clinical_status == "All",
terms_of_employment == "All"
) |>
group_by(academic_year, contract_levels, academic_employment_function, sex) |>
summarise(number = sum(number, na.rm = TRUE), .groups = "drop")
# % female within each function x contract level
pct_female <- all_staff |>
group_by(academic_year, contract_levels, academic_employment_function) |>
mutate(total = sum(number), pct_female = number / total * 100) |>
filter(sex == "Female") |>
ungroup()
pct_f_to_prof <- pct_female |>
filter(
academic_year == latest_year,
contract_levels == "Professor",
academic_employment_function == "Teaching only"
) |>
pull(pct_female) |>
round(0)
pct_f_prof <- pct_female_by_level |>
filter(academic_year == latest_year, contract_levels == "Professor") |>
pull(pct_female) |>
round(0)pct_female |>
filter(academic_year == latest_year) |>
ggplot(aes(x = academic_employment_function, y = pct_female,
fill = contract_levels)) +
geom_col(position = "dodge") +
geom_hline(yintercept = 50, linetype = "dashed", colour = uog_grey) +
scale_fill_manual(values = c(
"Professor" = uog_blue,
"Other senior academic" = uog_pink,
"Other contract level" = uog_grey
)) +
labs(
title = "% female by academic function and contract level",
subtitle = str_c("UK HE, ", latest_year, " (HESA Table 9)"),
x = "Academic employment function", y = "% female",
fill = "Contract level", caption = "Dashed line = parity"
) +
theme_uog() +
theme(legend.position = "right")pct_female |>
filter(academic_year == latest_year) |>
mutate(pct_female = round(pct_female, 1)) |>
select(contract_levels, academic_employment_function, pct_female) |>
pivot_wider(names_from = academic_employment_function, values_from = pct_female) |>
rename(`Contract level` = contract_levels) |>
flextable() |>
ft_uog() |>
add_footer_lines("Figures show % of staff in each cell who are female.")Contract level | Both teaching and research | Research only | Teaching only |
|---|---|---|---|
Other contract level | 48.5 | 50.1 | 54.8 |
Other senior academic | 42.5 | 38.7 | 53.6 |
Professor | 31.7 | 32.9 | 45.9 |
Figures show % of staff in each cell who are female. | |||
No matter which career level you look at, teaching-focused posts are more female-dominated than research-only or combined posts. At junior grades, women are the majority of teaching-focused staff. That majority does not hold at the top and among teaching-focused professors, women make up around ‘46’%, which is notably higher than their share of all professors (‘32’%), but they are no longer in the majority. Women dominate teaching-focused work at junior levels, yet still do not dominate it at the most senior level.
pct_female |>
filter(academic_employment_function == "Teaching only") |>
ggplot(aes(x = academic_year, y = pct_female,
colour = contract_levels, group = contract_levels)) +
geom_line(linewidth = 1) +
geom_point(size = 2) +
geom_hline(yintercept = 50, linetype = "dashed", colour = uog_grey) +
scale_colour_manual(values = c(
"Professor" = uog_blue,
"Other senior academic" = uog_pink,
"Other contract level" = uog_grey
)) +
labs(
title = "% female among teaching-only staff, by contract level",
subtitle = "UK HE sector over time (HESA Table 9)",
x = "Academic year", y = "% female", colour = "Contract level",
caption = "Dashed line = parity"
) +
theme_uog()Across every year in the data, teaching-focused academic staff at junior and mid-level grades have been majority female, while teaching-focused professors have remained below that threshold. The gap between the most junior and other senior grades is closing, so some work has been done on getting women to e.g., Senior Lecturer, but the gap to Prof is still very real, and very large.
The analysis above looks at what proportion of teaching-focused staff at each level are women. This section inverts that and looks at what proportion of professors of each sex are on teaching-focused contracts.
If women professors are more likely than men to hold teaching-focused roles, it means the type of professorship women hold is systematically different, even at the same nominal level of seniority.
# Table 9: professors by sex and function
prof_national <- table9 |>
filter(contract_levels == "Professor") |>
group_by(academic_year, sex, academic_employment_function) |>
summarise(number = sum(number, na.rm = TRUE), .groups = "drop")
# % of each sex's professors in each function
prof_function_pct <- prof_national |>
group_by(academic_year, sex) |>
mutate(total = sum(number), pct = number / total * 100) |>
ungroup()prof_function_pct |>
filter(academic_year == latest_year) |>
ggplot(aes(x = academic_employment_function, y = pct, fill = sex)) +
geom_col(position = "dodge") +
scale_fill_manual(values = c("Female" = uog_pink, "Male" = uog_blue)) +
labs(
title = "Distribution of academic function among professors, by sex",
subtitle = str_c("UK HE, ", latest_year, " (HESA Table 9)"),
x = "Academic employment function",
y = "% of professors of that sex", fill = "Sex"
) +
theme_uog()prof_function_pct |>
filter(academic_year == latest_year) |>
mutate(pct = round(pct, 1)) |>
select(sex, academic_employment_function, number, pct) |>
rename(
Sex = sex,
`Academic function` = academic_employment_function,
`N (FPE)` = number,
`% of that sex's professors` = pct
) |>
flextable() |>
merge_v(j = "Sex") |>
ft_uog() |>
colformat_num(j = "N (FPE)", big.mark = ",", digits = 0) |>
valign(j = "Sex", valign = "top")Sex | Academic function | N (FPE) | % of that sex's professors |
|---|---|---|---|
Female | Both teaching and research | 15,030 | 89.3 |
Research only | 695 | 4.1 | |
Teaching only | 1,100 | 6.5 | |
Male | Both teaching and research | 32,345 | 92.3 |
Research only | 1,415 | 4.0 | |
Teaching only | 1,295 | 3.7 |
In 2024/25, approximately 6.5% of women professors were on teaching-focused contracts, compared with around 3.7% of men. Women professors are roughly 1.8 times as likely as their male counterparts to be teaching-focused.
Around 1 in 15 female professors is on a teaching-focused contract, compared with around 1 in 27 male professors. A woman who has reached professor is nearly twice as likely as her male counterpart to be on a teaching-focused rather than a combined teaching-and-research contract. The headline figure of 32% female professors may therefore mask important nuances about how much progress has actually been made towards gender parity.
prof_function_pct |>
filter(academic_employment_function == "Teaching only") |>
ggplot(aes(x = academic_year, y = pct, colour = sex, group = sex)) +
geom_line(linewidth = 1) +
geom_point(size = 2) +
scale_colour_manual(values = c("Female" = uog_pink, "Male" = uog_blue)) +
labs(
title = "% of professors on teaching-only contracts, by sex",
subtitle = "UK HE sector (HESA Table 9)",
x = "Academic year", y = "% teaching only", colour = "Sex"
) +
theme_uog()Throughout the period covered by the data, women professors have consistently been more likely than men to hold teaching-focused contracts, and the lines move in parallel rather than converging. The gap has not closed over time, which points to something structural about how teaching-focused professorships are distributed by gender, rather than a transitional pattern that is gradually resolving itself.
One possible explanation for the overall gap is that it is driven by a particular type of institution. Using institution-level data (Table 17, full-time staff only), we can compare Russell Group universities with the rest of the sector. Jenkins and Wolf (2023) have noted that Russell Group institutions saw the fastest growth in teaching-focused staff between 2005/06 and 2018/19, despite historically having low starting points for such contracts, which makes this a reasonable place to look.
# Add Russell Group flag
table17 <- table17 |>
mutate(
russell_group = if_else(he_provider %in% russell_group,
"Russell Group", "Non-RG")
)
# Filter to professors
prof_by_group <- table17 |>
filter(
contract_levels == "Professor",
sex %in% c("Female", "Male"),
academic_employment_function %in% c(
"Teaching only", "Research only", "Both teaching and research"
)
) |>
group_by(academic_year, russell_group, sex, academic_employment_function) |>
summarise(n = sum(number, na.rm = TRUE), .groups = "drop")
# % of professors who are teaching-only, by sex and RG status
prof_pct_teaching <- prof_by_group |>
group_by(academic_year, russell_group, sex) |>
mutate(total_profs = sum(n), pct = n / total_profs * 100) |>
ungroup() |>
filter(academic_employment_function == "Teaching only")ggplot(prof_pct_teaching,
aes(x = academic_year, y = pct,
colour = sex, linetype = russell_group,
group = interaction(sex, russell_group))) +
geom_line(linewidth = 1) +
geom_point(size = 2) +
scale_colour_manual(values = c("Female" = uog_pink, "Male" = uog_blue)) +
labs(
title = "% of professors on teaching-only contracts",
subtitle = "Russell Group vs non-RG, by sex (HESA Table 17, full-time only)",
x = "Academic year", y = "% teaching only",
colour = "Sex", linetype = "Institution group"
) +
theme_uog()Whether looking at Russell Group universities or the rest of the sector, the pattern holds that women professors are more likely than men to be on teaching-focused contracts. The gap is not an artefact of institutional mix and it is not driven by a single type of university. It appears across both groups, which is consistent with something more systemic about who ends up in teaching-focused professorships.
prof_pct_female_rg <- prof_by_group |>
group_by(academic_year, russell_group, sex) |>
summarise(n = sum(n), .groups = "drop") |>
group_by(academic_year, russell_group) |>
mutate(total = sum(n), pct = n / total * 100) |>
filter(sex == "Female")
ggplot(prof_pct_female_rg,
aes(x = academic_year, y = pct,
colour = russell_group, group = russell_group)) +
geom_line(linewidth = 1) +
geom_point(size = 2) +
geom_hline(yintercept = 50, linetype = "dashed", colour = uog_grey) +
scale_colour_manual(values = c("Russell Group" = uog_blue, "Non-RG" = uog_pink)) +
labs(
title = "% of professors who are female",
subtitle = "Russell Group vs non-RG (HESA Table 17, full-time only)",
x = "Academic year", y = "% female",
colour = "Institution group"
) +
theme_uog()Women make up a smaller share of all professors in Russell Group universities than in the rest of the sector, and this gap has been persistent throughout the period. The most research-intensive institutions have the lowest female representation at professor level. Bear in mind that these figures cover full-time staff only, so the full picture is likely somewhat worse — women working part-time are not counted here, and women are more likely than men to work part-time.
# --- Summary table 1: % teaching-only among professors, by sex ---
summary_teaching_only <- prof_function_pct |>
filter(academic_year == latest_year,
academic_employment_function == "Teaching only") |>
mutate(pct = round(pct, 1)) |>
select(sex, number, total, pct) |>
rename(
Sex = sex,
`Teaching-only professors (FPE)` = number,
`All professors (FPE)` = total,
`% teaching-only` = pct
)
# --- Summary table 2: of teaching-only professors, % female ---
summary_composition <- prof_national |>
filter(academic_year == latest_year,
academic_employment_function == "Teaching only") |>
mutate(total = sum(number), pct = round(number / total * 100, 1)) |>
select(sex, number, pct) |>
rename(
Sex = sex,
`Teaching-only professors (FPE)` = number,
`% of teaching-only professors` = pct
)
# --- Summary table 3: of ALL teaching-only staff, % female ---
summary_all_to <- all_staff |>
filter(academic_year == latest_year,
academic_employment_function == "Teaching only") |>
group_by(sex) |>
summarise(n = sum(number), .groups = "drop") |>
mutate(total = sum(n), pct = round(n / total * 100, 1)) |>
select(sex, n, pct) |>
rename(
Sex = sex,
`Teaching-only staff (FPE)` = n,
`% of all teaching-only staff` = pct
)Sex | Teaching-only professors (FPE) | All professors (FPE) | % teaching-only |
|---|---|---|---|
Female | 1,100 | 16,825 | 6.5 |
Male | 1,295 | 35,055 | 3.7 |
This table shows what proportion of each sex’s professors are on teaching-focused contracts. In the most recent year of data, around 1 in 15 female professors held a teaching-focused contract, compared with around 1 in 27 male professors. Both percentages are small, but the relative difference is substantial.
Sex | Teaching-only professors (FPE) | % of teaching-only professors |
|---|---|---|
Female | 1,100 | 45.9 |
Male | 1,295 | 54.1 |
Looked at from the other direction, women make up around 46% of teaching-focused professors across the sector. That is notably higher than their 32% share of all professors, confirming that teaching-focused professorships are disproportionately held by women. Women are not the majority of teaching-focused professors as they are of teaching-focused staff at junior grades, though — the feminisation is real but diminishes at the top.
Sex | Teaching-only staff (FPE) | % of all teaching-only staff |
|---|---|---|
Female | 92,390 | 54.7 |
Male | 76,620 | 45.3 |
For comparison, this table shows the gender breakdown of all teaching-focused academic staff, not just professors. Women account for around 55% of all teaching-focused staff across the sector — they are the majority. Taken alongside the previous table, this confirms that women are overrepresented in teaching-focused roles at every level, but the degree of overrepresentation shrinks as seniority increases. At junior grades, women are the majority; among professors, they are not.
So what does all this mean? For me, the biggest takeaway from this analysis isn’t actually about gender, it’s the fact that less than 2% of people on teaching-only contracts make it to Prof compared to those on R&T contracts. I say this with every bone of my Professorial teaching-track body: What. The Absolute. Fuck. For many years I’ve felt lucky to be at UofG and indeed in my inaugural lecture I made the point that I’ve always worked at institutions where LTS Prof was a possibility and something to aim for and I think that’s had a clear impact on the work I have done and the pride I take in my career. But I did not realise just how lucky I am until I saw these figures.
My most plausible explanations for these numbers are a combination of optimism - teaching-focused career tracks are still relatively new and so maybe people just haven’t had the time to make it through to Prof yet - and pessimism and fury - many institutions still do not have a teaching-only route to Prof. My next adventure with Claude will be to see if the latter is true. It is unacceptable to increase the number of people on teaching-only contracts and not provide the mechanism for full career progression. ESPECIALLY WHEN THOSE PEOPLE ARE MORE LIKELY TO BE WOMEN. If you work at an institution that does not have a route to Prof and you would like me to come and shout at have a robust conversation with your senior management, please let me know.
I find the story the data tell about gender and career track harder to turn into a coherent viewpoint. Perhaps if I keep writing one will emerge. Bear with me.
Teaching-focused careers are a good thing. I feel very strongly that what is expected of both teaching and research by modern higher education mean that specialised tracks are necessary. I also feel very strongly that teaching-focused careers are not second-class in any way, shape, or form. I am a world-class Professor and my Professorship took just as much work and involves the same level of international standing and impact as an R&T Prof. I normally don’t even acknowledge the “second class” thing, in the same way I don’t acknowledge that some people think homosexuality is evil when I tell people I have a wife. Because it’s utter nonsense and why would I give air to the opinions of trolls and prime the idea that I am less than I am?
But there is a tension here because teaching-focused positions are more likely to be undertaken by women and we know from the history of everything and the patriarchy, that when a job is done by women, it’s undervalued. Except, this gets more complicated because whilst the majority of those on teaching-only contracts are women, the majority of teaching-only Profs are still men. So it turns out that there is prestige associated with teaching-only roles but the system is more likely to award it to men.
My lack of a coherent viewpoint stems from the fact I don’t know what I want these figures to show (aside from those teaching-only promotion figures going up). I don’t necessarily want there to be gender parity between tracks, what I want is for everyone to have the career they have chosen and for all career tracks to have equal recognition and support.
After I shared this blog, several conversations with colleagues have led to some UofG specific musings (am I as lucky as I think I am?).
Table 17 allows us to pull out a single institution and compare it against the Russell Group average and the rest of the sector. The figures below are for full-time staff across all contract terms.
# Glasgow professors by sex and function
glasgow_profs <- table17 |>
filter(
he_provider == "The University of Glasgow",
contract_levels == "Professor",
sex %in% c("Female", "Male"),
academic_employment_function %in% c(
"Teaching only", "Research only", "Both teaching and research"
)
) |>
group_by(academic_year, sex, academic_employment_function) |>
summarise(n = sum(number, na.rm = TRUE), .groups = "drop")
# % teaching-only among Glasgow professors, by sex
glasgow_pct_teaching <- glasgow_profs |>
group_by(academic_year, sex) |>
mutate(total = sum(n), pct = n / total * 100) |>
ungroup() |>
filter(academic_employment_function == "Teaching only")
# Compare: Glasgow vs RG average vs non-RG
# prof_pct_teaching already exists from the RG section
comparison <- bind_rows(
glasgow_pct_teaching |>
mutate(group = "University of Glasgow") |>
select(academic_year, sex, pct, group),
prof_pct_teaching |>
select(academic_year, sex, pct, group = russell_group)
)
latest_t17 <- max(comparison$academic_year)ggplot(comparison,
aes(x = academic_year, y = pct,
colour = sex, linetype = group,
group = interaction(sex, group))) +
geom_line(linewidth = 1) +
geom_point(size = 2) +
scale_colour_manual(values = c("Female" = uog_pink, "Male" = uog_blue)) +
scale_linetype_manual(values = c(
"University of Glasgow" = "solid",
"Russell Group" = "dashed",
"Non-RG" = "dotted"
)) +
labs(
title = "% of professors on teaching-only contracts",
subtitle = "Glasgow vs Russell Group vs non-RG (HESA Table 17, full-time only)",
x = "Academic year", y = "% teaching only",
colour = "Sex", linetype = "Group"
) +
theme_uog()Group | Female | Male |
|---|---|---|
University of Glasgow | 8.6 | 6.5 |
Non-RG | 5.0 | 2.8 |
Russell Group | 5.8 | 2.4 |
# % female among professors at Glasgow vs RG vs non-RG
glasgow_pct_female <- glasgow_profs |>
group_by(academic_year, sex) |>
summarise(n = sum(n), .groups = "drop") |>
group_by(academic_year) |>
mutate(total = sum(n), pct = n / total * 100) |>
filter(sex == "Female") |>
mutate(group = "University of Glasgow") |>
select(academic_year, pct, group)
comparison_female <- bind_rows(
glasgow_pct_female,
prof_pct_female_rg |>
select(academic_year, pct, group = russell_group)
)
ggplot(comparison_female,
aes(x = academic_year, y = pct,
colour = group, group = group)) +
geom_line(linewidth = 1) +
geom_point(size = 2) +
geom_hline(yintercept = 50, linetype = "dashed", colour = uog_grey) +
scale_colour_manual(values = c(
"University of Glasgow" = uog_green,
"Russell Group" = uog_blue,
"Non-RG" = uog_pink
)) +
labs(
title = "% of professors who are female",
subtitle = "Glasgow vs Russell Group vs non-RG (HESA Table 17, full-time only)",
x = "Academic year", y = "% female",
colour = "Group"
) +
theme_uog()Glasgow has a higher proportion of teaching-focused professors than either the Russell Group average or the non-RG sector, for both women and men. In the most recent year, 8.6% of Glasgow’s female professors were teaching-focused compared with the Russell Group average of 5.8%, and 6.5% of Glasgow’s male professors were teaching-focused compared with the RG average of 2.4%. This likely reflects the fact that Glasgow has a well-established teaching-focused career track with a route to professor, which is not universal across the sector.
Bear in mind that Glasgow’s numbers are for a single institution, so year-on-year fluctuations will be noisier than sector averages. Table 17 covers full-time staff only and all contract terms, so these figures are not directly comparable to the open-ended-only figures elsewhere in this post.
The national analysis showed that only a small percentage of teaching-only staff across the sector have reached professor. How does Glasgow compare? Using Table 17, we can compute the same figure for Glasgow specifically.
# % of teaching-only staff who are professors at Glasgow vs sector
glasgow_all <- table17 |>
filter(
he_provider == "The University of Glasgow",
sex %in% c("Female", "Male"),
contract_levels %in% c("Professor", "Other senior academic",
"Other contract level"),
academic_employment_function %in% c(
"Teaching only", "Research only", "Both teaching and research"
)
) |>
group_by(academic_year, academic_employment_function, contract_levels) |>
summarise(n = sum(number, na.rm = TRUE), .groups = "drop")
# Same for the full sector (from table17)
sector_all <- table17 |>
filter(
sex %in% c("Female", "Male"),
contract_levels %in% c("Professor", "Other senior academic",
"Other contract level"),
academic_employment_function %in% c(
"Teaching only", "Research only", "Both teaching and research"
)
) |>
group_by(academic_year, academic_employment_function, contract_levels) |>
summarise(n = sum(number, na.rm = TRUE), .groups = "drop")
# Compute % who are professors by function
compute_prof_rate <- function(df, label) {
df |>
filter(academic_year == latest_t17) |>
group_by(academic_employment_function) |>
summarise(
total = sum(n),
professors = sum(n[contract_levels == "Professor"]),
.groups = "drop"
) |>
mutate(
pct_professor = round(professors / total * 100, 1),
group = label
)
}
glasgow_rate <- compute_prof_rate(glasgow_all, "University of Glasgow")
sector_rate <- compute_prof_rate(sector_all, "All institutions")bind_rows(glasgow_rate, sector_rate) |>
select(group, academic_employment_function, total, professors, pct_professor) |>
rename(
Group = group,
`Academic function` = academic_employment_function,
`Total staff` = total,
Professors = professors,
`% who are professors` = pct_professor
) |>
flextable() |>
merge_v(j = "Group") |>
ft_uog() |>
colformat_num(j = c("Total staff", "Professors"), big.mark = ",", digits = 0) |>
valign(j = "Group", valign = "top")Group | Academic function | Total staff | Professors | % who are professors |
|---|---|---|---|---|
University of Glasgow | Both teaching and research | 12,420 | 5,140 | 41.4 |
Research only | 9,000 | 0 | 0.0 | |
Teaching only | 5,040 | 400 | 7.9 | |
All institutions | Both teaching and research | 1,389,865 | 305,630 | 22.0 |
Research only | 668,585 | 9,610 | 1.4 | |
Teaching only | 483,530 | 11,480 | 2.4 |
This table compares the proportion of teaching-only staff who have reached professor at Glasgow versus the sector as a whole (full-time, all contract terms). Note that these figures are from Table 17 and cover all contract terms (not just open-ended), so they are not directly comparable to the Table 9 figures earlier in this post (which cover all modes of employment rather than full-time only). However, the relative comparison between Glasgow and the sector is valid.
Clinical academics (those in medicine, dentistry, and veterinary science whose salaries are partly or wholly funded by the NHS) have a distinctive career structure. It is worth asking whether the teaching-only gender gap looks different for clinical vs non-clinical staff.
Table 9 includes a clinical_status dimension, but the main analysis filters to clinical_status == "All" (the aggregate). Here we read the raw data again, split by clinical status, and repeat the professor/function/sex analysis.
# Read Table 9 again without the clinical_status == "All" filter
t9_clinical <- map_dfr(t9_files, read_t9) |>
filter(
sex %in% c("Female", "Male"),
contract_levels == "Professor",
academic_employment_function %in% c(
"Teaching only", "Research only", "Both teaching and research"
),
mode_of_employment == "All",
country_of_he_provider == "All",
clinical_status %in% c("Clinical", "Non-clinical"),
terms_of_employment == "All"
) |>
group_by(academic_year, clinical_status, sex, academic_employment_function) |>
summarise(number = sum(number, na.rm = TRUE), .groups = "drop")
# % teaching-only among professors, by sex and clinical status
clinical_pct <- t9_clinical |>
group_by(academic_year, clinical_status, sex) |>
mutate(total = sum(number), pct = number / total * 100) |>
ungroup() |>
filter(academic_employment_function == "Teaching only")ggplot(clinical_pct,
aes(x = academic_year, y = pct,
colour = sex, linetype = clinical_status,
group = interaction(sex, clinical_status))) +
geom_line(linewidth = 1) +
geom_point(size = 2) +
scale_colour_manual(values = c("Female" = uog_pink, "Male" = uog_blue)) +
labs(
title = "% of professors on teaching-only contracts",
subtitle = "Clinical vs non-clinical, by sex (HESA Table 9)",
x = "Academic year", y = "% teaching only",
colour = "Sex", linetype = "Clinical status"
) +
theme_uog()clinical_pct |>
filter(academic_year == latest_year) |>
mutate(pct = round(pct, 1)) |>
select(clinical_status, sex, number, total, pct) |>
rename(
`Clinical status` = clinical_status,
Sex = sex,
`Teaching-only professors` = number,
`All professors` = total,
`% teaching-only` = pct
) |>
flextable() |>
merge_v(j = "Clinical status") |>
ft_uog() |>
colformat_num(j = c("Teaching-only professors", "All professors"),
big.mark = ",", digits = 0) |>
valign(j = "Clinical status", valign = "top")Clinical status | Sex | Teaching-only professors | All professors | % teaching-only |
|---|---|---|---|---|
Clinical | Female | 215 | 1,100 | 19.5 |
Male | 185 | 2,750 | 6.7 | |
Non-clinical | Female | 885 | 15,710 | 5.6 |
Male | 1,115 | 32,305 | 3.5 |
# Broader view: % who make it to professor, clinical vs non-clinical
t9_clinical_all <- map_dfr(t9_files, read_t9) |>
filter(
sex %in% c("Female", "Male"),
contract_levels %in% c("Professor", "Other senior academic",
"Other contract level"),
academic_employment_function %in% c(
"Teaching only", "Research only", "Both teaching and research"
),
mode_of_employment == "All",
country_of_he_provider == "All",
clinical_status %in% c("Clinical", "Non-clinical"),
terms_of_employment == "All"
) |>
group_by(academic_year, clinical_status, contract_levels, sex,
academic_employment_function) |>
summarise(number = sum(number, na.rm = TRUE), .groups = "drop")
clinical_prof_rate <- t9_clinical_all |>
filter(academic_year == latest_year) |>
group_by(clinical_status, sex, academic_employment_function) |>
summarise(
total_staff = sum(number),
professors = sum(number[contract_levels == "Professor"]),
.groups = "drop"
) |>
mutate(pct_professor = round(professors / total_staff * 100, 1))
clinical_prof_rate |>
select(clinical_status, sex, academic_employment_function,
total_staff, professors, pct_professor) |>
rename(
`Clinical status` = clinical_status,
Sex = sex,
`Academic function` = academic_employment_function,
`Total staff` = total_staff,
Professors = professors,
`% who are professors` = pct_professor
) |>
flextable() |>
merge_v(j = c("Clinical status", "Sex")) |>
ft_uog() |>
colformat_num(j = c("Total staff", "Professors"),
big.mark = ",", digits = 0) |>
valign(j = c("Clinical status", "Sex"), valign = "top")Clinical status | Sex | Academic function | Total staff | Professors | % who are professors |
|---|---|---|---|---|---|
Clinical | Female | Both teaching and research | 2,385 | 795 | 33.3 |
Research only | 2,425 | 90 | 3.7 | ||
Teaching only | 2,905 | 215 | 7.4 | ||
Male | Both teaching and research | 4,450 | 2,330 | 52.4 | |
Research only | 2,495 | 235 | 9.4 | ||
Teaching only | 2,120 | 185 | 8.7 | ||
Non-clinical | Female | Both teaching and research | 91,250 | 14,225 | 15.6 |
Research only | 49,160 | 600 | 1.2 | ||
Teaching only | 89,490 | 885 | 1.0 | ||
Male | Both teaching and research | 112,540 | 30,020 | 26.7 | |
Research only | 49,745 | 1,170 | 2.4 | ||
Teaching only | 74,505 | 1,115 | 1.5 |
The clinical/non-clinical split reveals a striking pattern. Among clinical professors, nearly one in five women (19.4%) is on a teaching-only contract, compared with around one in fifteen men (6.6%). That is a ratio of almost 3:1, substantially larger than the 1.7:1 ratio among non-clinical professors (5.5% women vs 3.3% men). The teaching-only gender gap is much more pronounced in clinical disciplines.
Equally notable is the promotion rate. Among clinical teaching-only staff, around 8-9% have reached professor, which is far higher than the 1.1-1.7% rate for non-clinical teaching-only staff. Clinical career structures appear to offer a more viable route to professor for teaching-focused academics of both sexes, but women in clinical teaching-only roles are still much less likely to reach professor than men in equivalent clinical roles (8.0% vs 9.2%), and the gap is vastly larger on combined contracts (37.0% vs 55.3%).
Note that clinical professors are a relatively small group, so individual cell sizes are small and percentages should be interpreted with caution. HESA’s rounding to the nearest 5 adds additional noise.