Una opción, altamente normalizada, es hacer que las tablas se parezcan más
create table notifications(
notification_id serial primary key,
date_created timestamp not null default now(),
title_id text not null,
message_id text not null,
icon text not null default 'logo'
);
create table usernotifications
(
notification_id integer references notifications,
user_id integer references users
);
create table groupnotifications
(
notification_id integer references notifications,
group_id integer references groups
);
create table companynotifications
(
notification_id integer references notifications,
company_id integer references companies
);
donde las entradas solo existen en la tabla de notificaciones relevante (usuario/empresa/grupo) para cualquier notificación dada.
(No creo que haya nada de malo con las claves foráneas anulables en la situación en la que eso indica que la clave foránea es opcional, pero múltiples claves foráneas de tipo similar dan la impresión de un diseño desnormalizado)