Uma opção, altamente normalizada, é tornar as tabelas mais parecidas com
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
);
onde as entradas só existem na tabela de notificações relevantes (usuário/empresa/grupo) para qualquer notificação.
(Não acho que haja algo errado com chaves estrangeiras anuláveis na situação em que isso indica que a chave estrangeira é opcional, mas várias chaves estrangeiras de tipo semelhante dão a impressão de um design desnormalizado)