You could put some BEFORE INSERT triggers on the student & teacher tables.
Let the triggers check if a certain flag in the persons table corresponds with the expected flag for that table.
The example below works only in a Postgresql RDBMS.
create table person (
id serial primary key,
first_name varchar(30),
last_name varchar(100),
person_type char(1) not null check (person_type in ('T','S')),
unique (first_name, last_name)
);
create table student_table (
student_id serial primary key,
person_id int,
grade int,
foreign key (person_id) references person(id),
unique (person_id)
);
create table teacher_table (
teacher_id serial primary key,
person_id int,
nickname varchar(30),
foreign key (person_id) references person(id),
unique (person_id)
);
insert into person (person_type, first_name, last_name) values
('S', 'Anna', 'Brandi')
, ('T', 'Bob', 'Modest')
Creating a UDF for the triggers to use
CREATE FUNCTION check_person_type()
RETURNS trigger
AS $check_person_type$
DECLARE current_person_type char(1);
DECLARE new_person_type varchar(1);
BEGIN
new_person_type := TG_ARGV[0];
SELECT INTO current_person_type person_type
FROM person
WHERE id = NEW.person_id;
-- teacher check
IF current_person_type = 'T' AND new_person_type != 'T' THEN
RAISE EXCEPTION 'Person with id % is a teacher', NEW.person_id;
END IF;
-- student check
IF current_person_type = 'S' AND new_person_type != 'S' THEN
RAISE EXCEPTION 'Person with id % is a student', NEW.person_id;
END IF;
RETURN NEW;
END;
$check_person_type$ LANGUAGE plpgsql;
The triggers
CREATE TRIGGER check_student_person_type BEFORE INSERT ON student_table
FOR EACH ROW EXECUTE PROCEDURE check_person_type('S');
CREATE TRIGGER check_teacher_person_type BEFORE INSERT ON teacher_table
FOR EACH ROW EXECUTE PROCEDURE check_person_type('T');
Doing something bad
-- Trying to enroll teacher Bob as a student
insert into student_table (person_id, grade)
select id, 99 as grade
from person
where (first_name, last_name) = ('Bob', 'Modest');
ERROR: Person with id 2 is a teacher
CONTEXT: PL/pgSQL function check_person_type() line 14 at RAISE
-- Trying to enroll Anna as a teacher
insert into teacher_table (person_id, nickname)
select id, 'sweety pie' as nickname
from person
where (first_name, last_name) = ('Anna', 'Brandi');
ERROR: Person with id 1 is a student
CONTEXT: PL/pgSQL function check_person_type() line 19 at RAISE
Trying better this time
insert into student_table (person_id, grade)
select id, 1 as grade
from person
where (first_name, last_name) = ('Anna', 'Brandi');
select * from student_table limit 1;
student_id | person_id | grade
---------: | --------: | ----:
2 | 1 | 1
insert into teacher_table (person_id, nickname)
select id, 'the goat' as nickname
from person
where (first_name, last_name) = ('Bob', 'Modest');
select * from teacher_table limit 1;
teacher_id | person_id | nickname
---------: | --------: | :-------
2 | 2 | the goat
db<>fiddle here